6

我需要一些关于 node.js 的异步特性的帮助。我有一个 for 循环,它从数据库中收集数据。“结果”是一个数组,然后应该将其返回给主函数。

user_collection.findOne({
            _id : uid
        }, function(error, user) {
            if(error)
                callback(error)
            else {
                for(var j = 0; j < user.contacts.length; j++) {
                    if(user.contacts[j].accepted == 'true') {
                        user_collection.findOne({
                            _id : user.contacts[j].contactId
                        }, function(error, user) {
                            result.push(user);
                        })
                    } 
                }
                callback(null, result);  // This callback executes before the for-loop ends, ofc
            }
        });

如何确保在循环完成后执行回调?

4

3 回答 3

11

您可能需要考虑使用辅助库,例如async https://github.com/caolan/async

它有助于保持代码更加一致..

在您的情况下,您可以查看forEach()方法

forEach(arr, iterator, callback)

使用列表中的项目和完成时的回调调用迭代器。

查看单元测试以获取示例

https://github.com/caolan/async/blob/master/mocha_test/each.js

于 2012-05-04T12:06:42.327 回答
2

使用 ES6 Promises(一个 Promise 库可用于旧版浏览器):

处理所有保证同步执行的请求(例如 1 然后 2 然后 3)

function asyncFunction (item, cb) {
  setTimeout(() => {
    console.log('done with', item);
    cb();
  }, 100);
}

let requests = [1, 2, 3].reduce((promiseChain, item) => {
    return promiseChain.then(new Promise((resolve) => {
      asyncFunction(item, resolve);
    }));
}, Promise.resolve());

requests.then(() => console.log('done'))

在没有“同步”执行的情况下处理所有异步请求(2 可能比 1 更快地完成)

let requests = [1,2,3].map((item) => {
    return new Promise((resolve) => {
      asyncFunction(item, resolve);
    });
})

Promise.all(requests).then(() => console.log('done'));

我就是这样做的

Promise.all(body.schedules.map(function(scheduleId) {
        return new Promise(function(resolve, reject) {
            return scheduleSchema.findOneAndRemove({
                    _id: scheduleId
                })
                .then(function() {
                    logSchema.insert({
                        userId: req.user.id,
                        actId: constants.LOG_SCHEDULE_DELETE.id,
                        extData: scheduleId
                    });
                    resolve();
                })
                .catch(function(err) {
                    reject(err);
                });
        });
    })).then(function() {
        return res.json({
            code: constants.SUCCESS_CODE
        });
    }).catch(function(err) {
        return res.json(constants.DATABASE_ERROR);
    });

最后一个例子

function callback (result) { console.log('all done'); }

[1, 2, 3].forEach((item, index, array) => {
  asyncFunction(item, () => {
    if (index === array.length - 1) {
      callback();
    }
  });
});

这并不能保证回调将在处理完所有项目后执行。它只保证回调将在处理完最后一项后执行。

更多信息

迈克尔。

于 2016-08-02T15:34:49.227 回答
0

使用 Async.js v1.5.2,它是每个.

each(arr, iterator, [callback])

arr - 要迭代的数组。
iterator(item, callback) - 应用于 arr 中每个项目的函数。
回调(错误) - 可选。当所有迭代器函数完成或发生错误时调用的回调。

于 2016-02-01T07:36:09.680 回答