我试图将工作流转换为使用promises,因为它是一个可怕的回调鼠标,我一直很顺利,直到我找到一个特定的功能。我试图使用promFified版本的readFile()来获取一系列文件的内容,但我还需要保留每个文件的文件名,以便将它添加到最终将会出现的对象中。从下一步/函数中的文件内容中解析。只有当我遍历文件名列表(并创建promises以返回文件内容)时,才能访问此文件名。现在我有了这个,但是没有工作:
// Accepts a sequence of filenames and returns a sequence of objects containing article contents and their filenames
function getAllFiles(filenames) {
var files = []; // This will be an array of objects containing Promises on which we want to call .all()
filenames.each( function (filename) {
files.push({content: fsPromise.readFileAsync(articlesPath + '/' + filename, 'utf8'),
filename: filename});
});
这是尝试表达我下一步要做的事情:
Promise.all(files).then( function(files) {
return Lazy(files);
});
}
换句话说,我想从promises数组中得到的是像{content: "FILE CONTENTS", filename: "fileN.txt"}
这样的对象数组。第一部分是readFileAsync()
的结果,所以它是一个需要解决的承诺才能继续下一步。据我所知,filenames.each()
调用是我唯一的机会将文件内容与它来自的文件名相关联。我无法控制文件的内容,所以我无法将文件名存储在文件内容中,这将是丑陋的数据冗余,无论如何都是个坏主意。 Lazy()调用只是将已完成的数组转换为lazy.js序列,因为这是我在项目其余部分中用于集合处理的库。
是否可以从对象中提取promise部分并将它们存储在一个单独的数组中,然后在其上调用.all()
?换句话说,当所有的promise都完成后,我会回到原始数组并通过索引检索匹配的文件名?如果我能够使用引用将第二个数组填充到原始承诺(即我知道原件何时已解决),我觉得这样可行。这会有用吗?
我可以在.each()
电话中同步吗?例如。
filenames.each( function(filename) {
files.push({content: fsPromise.readFileAsync(articlesPath + '/' + filename, 'utf8')
.then( function(fulfilledContent) {return fulfilledContent}),
filename: filename
});
(我知道我也需要处理这些承诺被拒绝而不是解决的可能性 - 如果我已经解决了我试图做的事情,我会弄清楚如何做到这一点做甚至可能)
答案 0 :(得分:5)
有两个简单的解决方案:
访问上次回调中的filenames
数组。它与Promise.all
将满足的内容数组的顺序相同:
Promise.all(filenames.map(function(filename) {
return fsPromise.readFileAsync(articlesPath + '/' + filename, 'utf8');
})).then(function(contents) {
return Lazy(contents).map(function(content, i) {
return {content: content, filename: filenames[i]};
});
})
在迭代数组时立即为包含文件名和内容的对象做出承诺:
Promise.all(filenames.map(function(filename) {
return fsPromise.readFileAsync(articlesPath + '/' + filename, 'utf8').then(function(content) {
return {content: content, filename: filename};
});
})).then(Lazy);