我试图将承诺链接在一起以提出一系列请求。这是我使用过承诺的少数几次之一,所以我不太清楚我在做什么。希望有人可以发现什么是错误的。基本上,我的第一个承诺是正常工作,然后第二个函数在第一个承诺解决后运行,但是,第三个函数不等待,因此我请求的信息不完整。
我可以看到我的函数正在返回正确的信息。所以主要是我的问题是如何格式化我的承诺,以便他们在运行之前等待彼此完成?
function getPaths(folderpath) {
return new Promise(function(resolve, reject) {
db.getPaths(folderpath, function(response) {
//get paths for files and folders
for (let i = 0; i < response.entries.length; i++) {
let entries = response.entries[i];
if (entries[".tag"] == "folder") {
folderPaths.push(response.entries[i].path_lower);
}
if (entries[".tag"] == "file") {
filePaths.push(response.entries[i].path_lower);
}
}
resolve();
});
});
}
function openFolders(folders) {
return new Promise(function(resolve, reject) {
for (let i = 0; i < folders.length; i++) {
db.getPaths(folders[i], function(response) {
for (let j = 0; j < response.entries.length; j++) {
let entries = response.entries[j];
if (entries[".tag"] == "file") {
filePaths.push(response.entries[j].path_lower);
}
}
//console.log(filePaths); //returns correct information
});
}
resolve();
});
}
getPaths("/path").then(function() {
openFolders(folderPaths);
}).then(function() {
console.log(filePaths); //returns incomplete information
});
答案 0 :(得分:3)
您在粗体
中遇到了一个大问题
function openFolders(folders) {
return new Promise(function(resolve, reject) {
for (let i = 0; i < folders.length; i++) {
db.getPaths(folders[i], function(response) {
// ...
});
}
resolve();
});
}
您正在围绕异步函数调用运行同步 for
循环。循环完成同步迭代,然后立即调用resolve()
- 异步处理程序中的代码(例如,filePaths.push(...)
)在 Promise被解析之前不运行
但你的问题并没有止步于此。您通过修改全局状态然后解析并清空Promise - resolve()
vs resolve(someValue)
来非常规地使用Promises。 @ FrankModica的答案还有更多的话要说。
至于补救措施,我建议你看看Promise.all
- 一般情况下,以更传统的方式使用Promise
在下面的代码段中,我嘲笑了您的db
函数,以便从虚假的内存数据库中读取fakedb
。然后,我创建了一个getPaths
函数,它包装了db.getPaths
,但却返回了一个Promise。然后我重写openFolders
来创建一个Promises数组,将它们传递给Promise.all
,然后最终解析我想要的值
值得注意的是:Promise.all
将在 parallel 中运行您的Promise数组 - 如果这不受欢迎,您可以使用.reduce
和.then
连续运行它们。
const db = {
getPaths: (path, k) => {
setTimeout(k, 50, fakedb[path])
}
}
function getPaths (path) {
return new Promise((resolve, reject) =>
db.getPaths(path, response => resolve(response)))
}
function openFolders (folders) {
return Promise.all(folders.map(getPaths))
.then(responses =>
responses.reduce((acc, {entries}) =>
acc.concat(entries.filter(x => x['.tag'] === 'file').map(x => x.path_lower)), []))
}
const fakedb = {
'cat': {
'entries': [
{ '.tag': 'dir', 'path_lower': './cat/.' },
{ '.tag': 'dir', 'path_lower': './cat/..' },
{ '.tag': 'file', 'path_lower': './cat/a' },
{ '.tag': 'file', 'path_lower': './cat/b' },
{ '.tag': 'file', 'path_lower': './cat/c' }
]
},
'dog': {
'entries': [
{ '.tag': 'dir', 'path_lower': './dog/.' },
{ '.tag': 'dir', 'path_lower': './dog/..' },
{ '.tag': 'file', 'path_lower': './dog/a' },
{ '.tag': 'file', 'path_lower': './dog/b' },
{ '.tag': 'file', 'path_lower': './dog/c' }
]
}
}
openFolders(['cat','dog']).then(console.log, console.error)
&#13;
我在openFolders
中执行的操作可能会感觉有点复杂,因为它会处理responses
处理程序中.then
的所有转换 - 您可以( (可选))将工作分成多个.then
调用,这可能会导致较轻的认知负荷
function openFolders (folders) {
return Promise.all(folders.map(getPaths))
// get `.entries` of each response
.then(responses =>
responses.map(x => x.entries))
// flatten array of entries arrays into a single array
.then(arrOfEntries =>
arrOfEntries.reduce((acc, entries) =>
acc.concat(entries), []))
// only keep entries where `.tag` of each entry is `'file'`
.then(entries =>
entries.filter(x => x['.tag'] === 'file'))
// return `path_lower` of the resulting entries
.then(entries =>
entries.map(x => x.path_lower))
}
答案 1 :(得分:2)
如果我理解正确,您正在使用外部范围(folderPaths
和filePaths
)中的一些变量。我不确定这是解决这个问题的最佳方法,但我相信一旦你从openFolders
返回承诺,它就会开始工作。这样你就等到openFolders
完成了:
getPaths("/path").then(function() {
return openFolders(folderPaths);
}).then(function() {
console.log(filePaths);
});
但我建议您解决下次通话所需的信息:
resolve(folderPaths);
和
resolve(filePaths);
所以你的代码看起来更像是:
getPaths("/path").then(function(folderPaths) {
return openFolders(folderPaths);
}).then(function(filePaths) {
console.log(filePaths);
});
修改:看起来您可能还有@naomik提到的其他问题。如果db.getPaths
是异步的,则在openFolders
函数中,您可能会在循环中的所有异步调用完成之前解析。不幸的是,我现在没有时间来展示解决方案。希望@naomik可以!