2017-07-25 143 views
0

我有许多函数可以在循环中为不同的数据执行几次异步函数。我要等到所有异步功能将被执行,然后解析(),(或称非承诺函数回调函数)等待很多异步函数执行

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()

它很好用,但看起来不够优雅和可读。你知道这个问题有更好的办法吗?

+3

[Promise.all()](HTTPS://developer.mozilla。 org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all)将非常合适!而不是一个大的承诺,将个体较小的承诺推向一个数组。然后,使用'承诺。all()'等待所有的承诺解决。 – dpaulus

+0

我不知道这个功能,谢谢! –

+2

请注意,你正在做的是解决这个问题的正确方法;你的编码器本能就是关键。 'Promise.all'将简单地为你做好准备,保持你的代码清洁。另外 - 你可能想使用'fs-extra',一个替代'fs'的插件,但是增加了promise的支持。 – Amadan

回答

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

你只需要推动所有的承诺变成一个数组,然后把它作为参数传递给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); 
} 
+0

感谢您的努力! –

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)) 
+0

确实看起来很干净! :) 非常感谢 –