我有promise函数,可以在循环中执行几次不同数据的异步函数。我想等到所有异步函数都被执行然后解析(),(或在非承诺函数中调用回调函数):
var readFiles = ()=>{
return new Promise((resolve,reject)=>{
var iterator = 0;
var contents = {};
for(let i in this.files){
iterator++;
let p = path.resolve(this.componentPath,this.files[i]);
fs.readFile(p,{encoding:'utf8'},(err,data)=>{
if(err){
reject(`Could not read ${this.files[i]} file.`);
} else {
contents[this.files[i]] = data;
iterator--;
if(!iterator) resolve(contents);
}
});
}
if(!iterator) resolve(contents); //in case of !this.files.length
});
};
我在每次循环重复时增加iterator
,然后在async函数的回调减少iterator
中检查是否所有异步函数都已完成(iterator === 0),如果是 - 致电resolve()
。
效果很好,但似乎不优雅和可读。你知道更好的解决这个问题的方法吗?
答案 0 :(得分:2)
使用一些代码和更多细节跟进评论!
Promise.all()
接受迭代器,并等待所有承诺解析或拒绝。然后它将返回所有承诺的结果。因此,我们可以创建很少的承诺并将它们添加到数组中,而不是跟踪所有承诺何时解决。然后,使用Promise.all()等待所有这些解析。
const readFiles = () => {
const promises = [];
for(let i in files) {
const p = path.resolve(componentPath, files[i]);
promises.push(new Promise((resolve, reject) => {
fs.readFile(p, {encoding:'utf8'}, (err, data) => {
if(err) {
reject(`Could not read ${files[i]} file.`);
} else {
resolve(data);
}
});
}));
}
return Promise.all(promises);
};
const fileContents = readFiles().then(contents => {
console.log(contents)
})
.catch(err => console.error(err));
答案 1 :(得分:1)
您只需将所有Promises推送到数组中,然后将其作为参数传递给Promise.all(arrayOfPromises)
尝试这样的事情:
var readFiles = () => {
var promises = [];
let contents = {};
var keys_files = Object.keys(this.files);
if (keys_files.length <= 0) {
var promise = new Promise((resolve, reject) => {
resolve(contents);
});
promises.push(promise);
}
keys_files.forEach((key) => {
var file = this.files[key];
var promise = new Promise((resolve, reject) => {
const currentPath = path.resolve(this.componentPath, file);
fs.readFile(p,{encoding:'utf8'},(err, data) => {
if (err) {
return reject(`Could not read ${file} file.`);
}
contents[file] = data;
resolve(contents)
});
});
});
return Promises.all(promises);
}
然后你应该使用这样的函数:
// this will return a promise that contains an array of promises
var readAllFiles = readFiles();
// the then block only will execute if all promises were resolved if one of them were reject so all the process was rejected automatically
readAllFiles.then((promises) => {
promises.forEach((respond) => {
console.log(respond);
});
}).catch((error) => error);
如果您不在乎其中一项承诺被拒绝,也许您应该执行以下操作
var readFiles = () => {
var promises = [];
let contents = {};
var keys_files = Object.keys(this.files);
if (keys_files.length <= 0) {
var promise = new Promise((resolve, reject) => {
resolve(contents);
});
promises.push(promise);
}
keys_files.forEach((key) => {
var file = this.files[key];
var promise = new Promise((resolve, reject) => {
const currentPath = path.resolve(this.componentPath, file);
fs.readFile(p,{encoding:'utf8'},(err, data) => {
// create an object with the information
let info = { completed: true };
if (err) {
info.completed = false;
info.error = err;
return resolve(info);
}
info.data = data;
contents[file] = info;
resolve(contents)
});
});
});
return Promises.all(promises);
}
答案 2 :(得分:1)
复制评论:
此外 - 您可能希望使用
fs-extra
,fs
的替代品,但添加了承诺支持。
这是怎么回事:
const fs = require('fs-extra');
var readFiles = ()=>{
let promises = files
.map(file => path.resolve(componentPath, file))
.map(path => fs.readFile(path));
return Promise.all(promises);
});
干净整洁。然后,您可以获得以下内容:
readFiles()
.then(contents => { ... })
.catch(error => { ... });
这会在第一次出错时失败(因为那是Promise.all
所做的事情)。如果您需要单独的错误处理,可以添加另一个map
行:
.map(promise => promise.catch(err => err));
然后你可以过滤结果:
let errors = contents.filter(content => content instanceof Error)
let successes = contents.filter(content => !(content instanceof Error))