ES6承诺——类似async.each

ES6 Promises - something like async.each?

本文关键字:each async 类似 ES6 承诺      更新时间:2023-09-26

试图找出如何找到功能完全像async的东西。每个系列,我需要一个异步动作的列表按顺序运行(不是并行),但无法找到一种方法来做它在原生ES6,谁能建议,请?

注。我想过发电机/产量,但我还没有经验,所以我不知道它到底能帮我什么。

编辑1

每个请求,这里有一个例子:

假设代码如下:

let model1 = new MongooseModel({prop1: "a", prop2: "b"});
let model2 = new MongooseModel({prop1: "c", prop2: "d"});
let arr = [model1 , model2];

现在,我想把它串联起来,而不是并行地运行,所以使用"async"NPM很容易:

async.eachSeries(arr, (model, next)=>{
    model.save.then(next).catch(next);
}, err=>{
    if(err) return reject(error);
    resolve();
})

我的问题是:在ES6中,我可以自己做吗?没有NPM的async包?

编辑2

使用async/await可以很容易地完成:

let model1 = new MongooseModel({prop1: "a", prop2: "b"});
let model2 = new MongooseModel({prop1: "c", prop2: "d"});    
let arr = [model1 , model2];
for(let model of arr){
    await model.save();
}

喜欢简短回答的人:

[func1, func2].reduce((p, f) => p.then(f), Promise.resolve());

假设你想在一个数据数组上调用一些异步函数,并且你希望它们顺序调用,而不是并行调用。

async.eachSeries()的接口是这样的:

eachSeries(arr, iterator, [callback])

下面是如何用promise来模拟:

// define helper function that works kind of like async.eachSeries
function eachSeries(arr, iteratorFn) {
    return arr.reduce(function(p, item) {
        return p.then(function() {
            return iteratorFn(item);
        });
    }, Promise.resolve());
}

假设iteratorFn接受要处理的项目作为参数,并返回一个promise。

这里有一个使用示例(假设您有一个承诺的fs.readFileAsync()),并有一个名为speak()的函数,该函数在完成时返回一个承诺:

 var files = ["hello.dat", "goodbye.dat", "genericgreeting.dat"];
 eachSeries(files, function(file) {
     return fs.readFileAsync(file).then(function(data) {
         return speak(data);
     });
 });

这让承诺基础结构为您排序所有内容。


你也可以手动排序(虽然我不确定为什么):

function eachSeries(arr, iteratorFn) {
    return new Promise(resolve, reject) {
        var index = 0;
        function next() {
            if (index < arr.length) {
                try {
                    iteratorFn(arr[index++]).then(next, reject);
                } catch(e) {
                    reject(e);
                }
            } else {
                resolve();
            }
        }
        // kick off first iteration
        next();
    });
}

或者,一个更简单的版本,手动将承诺链接在一起:

function eachSeries(arr, iteratorFn) {
    var index = 0;
    function next() {
        if (index < arr.length) {
            return iteratorFn(arr[index++]).then(next);
        }
    }
    return Promise.resolve().then(next);
}

注意其中一个手动版本必须用try/catch包围iteratorFn(),以确保它是抛出安全的(将异常转换为拒绝)。.then()是自动抛出安全的,所以其他方案不需要手动捕获异常,因为.then()已经为您捕获了异常。

作为@jib提供的答案的延伸…还可以将数组项映射到async函数,如下所示:

[item1, item2]
    .map(item => async (prev_result) => await something_async(item))
    .reduce((p, f) => p.then(f), Promise.resolve())
    .then(() => console.log('all done'));

请注意,prev_result将是之前对something_async求值所返回的值,这大致相当于async.eachSeriesasync.waterfall的混合体。

您可以通过在then回调中返回来链接。例如:

new Promise(function(resolve, reject){ 
  resolve(1)
}).then(function(v){
  console.log(v);
  return v + 1;
}).then(function(v){
  console.log(v)
});

将打印:

1

2

这当然适用于异步解析承诺:

new Promise(function(resolve, reject){
  setTimeout(function(){
    resolve(1);
  }, 1000)
}).then(function(result){
   return new Promise(function(resolve, reject){
     setTimeout(function(){
       console.log(result);
       resolve(result + 1);
     }, 1000)
   });
}).then(function(results){
  console.log(results);
});
印刷:

1

2

//为运行较低nodejs版本的系统上传此文件(Azure:/)不是我能想到的最短的,但是最好的

举个例子,我们说"functionWithPromise"返回一些承诺并期望一些项目。

functionWithPromise(item);
promisesArray =[];
//syncornized
itemsArray.forEach(function (item){
   promisesArray.push(functionWithPromise(item));
});
Promise.all(promisesArray).then(function (values){
//profit
});