等待很多异步函数执行
我有许多函数可以在循环中为不同的数据执行几次异步函数。我要等到所有异步功能将被执行,然后解析(),(或称非承诺函数回调函数):等待很多异步函数执行
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
在每个循环重复,那么,在异步函数的回调降低iterator
并检查是否所有的异步函数都已完成(迭代器=== 0),如果是这样 - 请致电resolve()
。
它很好用,但看起来不够优雅和可读。你知道这个问题有更好的办法吗?
继续注释一些代码和更多细节!
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));
你只需要推动所有的承诺变成一个数组,然后把它作为参数传递给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);
}
感谢您的努力! –
从评论复制:
而且 - 你可能想使用
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))
确实看起来很干净! :) 非常感谢 –
[Promise.all()](HTTPS://developer.mozilla。 org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all)将非常合适!而不是一个大的承诺,将个体较小的承诺推向一个数组。然后,使用'承诺。all()'等待所有的承诺解决。 – dpaulus
我不知道这个功能,谢谢! –
请注意,你正在做的是解决这个问题的正确方法;你的编码器本能就是关键。 'Promise.all'将简单地为你做好准备,保持你的代码清洁。另外 - 你可能想使用'fs-extra',一个替代'fs'的插件,但是增加了promise的支持。 – Amadan