在nodejs中循环的异步问题

时间:2016-12-16 10:46:08

标签: javascript node.js

我尝试迭代抛出一个项目列表,并通过调用这个例子的API对它们执行一些操作:

  for (i = 0; i < arr.length; i++) {  
    if (arr[i].id == 42) {
      api.requestAction(arr[i].id, function(error, response){ });
    }
 }

问题是在所有请求完成并且程序退出之前,循环显然已经结束。我应该怎么做来管理它?我看到了#34; Promise&#34;方法,但在这种情况下我真的不知道如何使用它,或者可能还有另一种解决方案。

提前谢谢你!

4 个答案:

答案 0 :(得分:1)

您可以使用async.js。它是一个异步控制流程库,为顺序循环,parralel中的循环以及许多其他常见的流控制机制提供控制流程,请查看它。

请参阅下面的代码,代码假设您已变量&#39; arr&#39;在范围的某处定义。

npm install async

     var async = require("async");




     //Loop through each item, waiting for your
     //asyncronous function to finish before continuing
     //to move onto the next item in the array
     //NOTE: This does not loop sequentially, if you want that function with asyncjs then user eachSeries
     async.each(arr, 

         //Item is the current item being iterated over,
         //callback is the callback you call to finish the current iteration, it accepts an error and result parameter callback(error, result);
         function (item, callback) {
              api.requestAction(item.id, function(error, response){ 

                   //Check for any errors...     
                   if (error) return callback(error);
                   callback(null);
              });
         },
         function (err, result) {
              //You've now finished the loop

              if (err) {
                 //Do something, you passed an error object to
                 //in one of the loop's iterations
              }

              //No errors, move on with your code..
         });

答案 1 :(得分:1)

使用node-fetch(一个promisify http api),您可以与async / await一起暂停for循环直到它完成,但这需要添加--harmony-async-await标志的节点v6 +

const fetch = require('node-fetch')

async function foo() {
  for (let item of arr) {
    if (item.id == 42) {
      let res = await fetch(url)
      let body = await res.text()
      console.log(body)
    }
  }
  console.log('done (after request)')
}

现在每次在函数前面添加async关键字时,它总会返回一个在一切完成后解析/拒绝的承诺

foo().then(done, fail)
如果你不想安装node-fetch,你可以将你的api fn包裹在承诺中

await new Promise((rs, rj) => {
  api.requestAction(arr[i].id, function(error, response){
    error ? rj(error) : rs(response)
  })
}) 

答案 2 :(得分:1)

安装bluebird

npm install bluebird --save

<强>代码

//require npm
var Promise = require("bluebird");

//code
//"promisify" converts traditional callback function into a Promise based function
var _requestAction = Promise.promisify(api.requestAction);

//loop over array
Promise.map(arr, function (value) {
    if (value.id == 42) {
        //async request
        return _requestAction(value.id).then(function (_result) {
            //success
            console.log(_result);
        }).catch(function (e) {
            //error
            console.error(e);
        });
    }
});

答案 3 :(得分:0)

使用蓝鸟承诺:

var Promise = require('bluebird');

Promise.map(arrayOfIds, function(item){
  return api.requestAction(item);
})
.then(function(response){
 // all the requests are resolved here
})

如果你想要顺序执行id,那么使用Promise.mapSeries(在等待任务完成时很慢)