NodeJS:for循环和promises

时间:2014-10-10 11:24:36

标签: node.js promise

异步编程比同步编程困难得多。

使用nodeJS,我正在尝试以下方法:

for (var i = 0; i < 10; i++) {
    someFunction().then(function() {
        // Do stuff
    });
}

但我希望循环只在Do Stuff部分完成时继续。

知道如何轻松实现这一目标......?

谢谢!

8 个答案:

答案 0 :(得分:4)

扩展Anders&#39;回答,这就是我过去处理这个问题的方式,需要等待多个承诺:

var promises = [];

for (var i = 0; i < 10; i++) {
    promises.push(someFunction().then(function() {
            // Do stuff
        })
    );
}

Q.all(promises)
.then(function() {
    // Do all the things!
})

答案 1 :(得分:3)

异步编程可能会让人感到困惑,但是如果你记住回调和then之类的事情将在以后运行,在它们包含的代码块已经完成之后,可以消除大部分的混乱。 。

Promise库,async模块,都试图更好地控制程序的流程。这是一个good article解释不同的方法,通过看到针对同一问题的不同替代解决方案,真正帮助我理解事物。

其他几个答案提到Q.all()。如果您已经拥有一系列承诺,这很有效。

如果您有一组值或承诺,那么还有另一个库可以使这更容易,称为bluebird。它有一个名为.map()的方法,您可以使用它来启动带数组的promise链。

使用这种方法,您不需要调用异步,promise-returning函数,将返回的promise存储在数组中,然后将该数组传递给Q.all。它可以为您节省一些步骤。

所以,假设你有一个只有值的数组:

var items = [0,1,2,3,4,5,6,7,8,9];

您可以执行以下操作:

Promise.map(items, function (item) {
  return performAsyncOperation(item);
}, {concurrency: n})
.then(function(allResults){
  //  'allResults' now contains an array of all
  //  the results of 'performAsyncOperation'
})

注意:为了使其按预期工作,performAsyncOperation必须返回承诺

另请注意 Promise.map()的第3个参数:{concurrency: n}。如果指定了此选项,bluebird将仅允许一次执行n个操作,如果您有大量要处理的项目,如果它们全部被立即启动,那么这将非常有用(网络连接,文件句柄等)。

最后说明:这是bluebird API doc。它写得非常好,有大量的例子,是探索承诺如何帮助您的生活更轻松的好方法。

希望它有所帮助!

答案 2 :(得分:2)

我喜欢在这种情况下使用的模式是定义一个异步操作完成后调用自身的函数。你的例子将是:

var times   = 10;
var current = 0;

(function nextLap() {
    if (current >= times) {
        return callback();
    }

    ++current;

    someFunction()
    .then(function() {
        // do stuff
        nextLap();
    })
    .catch(callback);
})();

答案 3 :(得分:1)

在继续

之前,使用Q.all等待所有承诺解决

答案 4 :(得分:1)

您可以使用reduce链接您的承诺:

array.reduce(function(promise, elt) {
    return promise.then(function() { return long_process(elt); });
}, new Promise.resolve());

此表达式的结果将是已完成的操作序列的承诺。这个代码不会只调用十个异步操作并等待它们全部完成,而是等到第一个操作完成后再开始第二个操作,如果这很重要的话。

答案 5 :(得分:0)

我也有类似的需要,我必须查询一个分页的api,直到找到匹配项或遍历每个页面为止。我们在每次调用中返回total_count。

const request = require('request-promise');
var total_count;
function findItem(uri, authorization, find_string, start_index, page_size) {        
    return new Promise((resolve, reject) => {
        const options = buildGetOptions(uri, authorization, start_index, page_size);
        request(options)
        .then((res) => {
            const count = JSON.parse(res).total_count;
            if (total_count != count) {                
                total_count = count;
            }
            if (JSON.parse(res).things.some(s => s.name === find_string)) {
                resolve(true);
            } else if (start_index >= total_count) {
                resolve(false);
            } else {
                resolve(findItem(uri, authorization, find_string, start_index + page_size, page_size));
            }
        })
        .catch((err) => {
            reject(err);
        });
    });
}
function buildGetOptions(uri, authorization, start_index, page_size) {
    return {
        method: 'GET',
        uri: uri + `?start_index=${start_index}&page_size=${page_size}`,
        headers: {
            'cache-control': 'no-cache',
            'content-type': 'application/json',
            'Authorization': authorization
        }
    };
}

答案 6 :(得分:0)

更简单,使用:

  

forEach 等待

示例:

var myarray = [1,2,3];
myarray.forEach(async i => {
    await someFunction().then(function() {
       // Do stuff
    });
});

答案 7 :(得分:0)

This article帮助我更好地理解了Promises,希望对您有所帮助:)