民间, 我有以下功能,我想知道只有当数据库操作在所有项目上完成时才调用callback()的正确方法:
function mapSomething (callback) {
_.each(someArray, function (item) {
dao.dosomething(item.foo, function (err, account) {
item.email = account.email;
});
});
callback();
},
我需要迭代someArray
并为每个元素执行数据库调用。替换数组中的所有项后,我只需要调用回调。当然,回调现在是在错误的地方
谢谢!
答案 0 :(得分:3)
您目前拥有它的方式,callback
在任何(异步)任务完成之前执行。
async
模块有each()
,可以进行最终回调:
var async = require('async');
// ...
function mapSomething (callback) {
async.each(someArray, function(item, cb) {
dao.dosomething(item.foo, function(err, account) {
if (err)
return cb(err);
item.email = account.email;
cb();
});
}, callback);
}
答案 1 :(得分:2)
在调用callback()
之前,这不会等待所有数据库调用完成。它将同时并行启动所有数据库调用(我假设dao.dosomething()
是什么)。然后,在任何数据库调用完成之前立即调用callback()
。
您有多种选择来解决问题。
Promise.all()
等待所有数据库调用完成。async
库来管理协调。我建议使用选项1.或2.就个人而言,我更喜欢使用promises,因为你正在与数据库接口,这可能不是你进行数据库调用的唯一地方,所以我会宣传接口(bluebird会在一个函数调用中为你做这个),然后使用promises。
这是承诺解决方案的样子:
var Promise = require('bluebird');
// make promise version of your DB function
// ideally, you'd promisify the whole DB API with .promisifyAll()
var dosomething = Promise.promisify(dao.dosomething, dao);
function mapSomething (callback, errCallback) {
Promise.all(_.map(someArray, function(item) {
return dosomething(item.foo).then(function (account) {
item.email = account.email;
});
}).then(callback, errCallback);
}
这假设您希望并行运行所有数据库调用,然后在完成后调用回调。
仅供参考,这是a link to how Bluebird promisify's现有的API。我将这种机制用于节点中的所有异步文件I / O,它节省了大量的编码时间,使错误处理更加清晰。异步回调是正确错误处理的噩梦,特别是如果可以从异步回调中抛出异常。
P.S。您实际上可能希望您的mapSomething()
函数只返回一个promise本身,因此调用者负责指定他们自己的.then()
处理程序,它允许调用者使用返回的promise来与其他东西同步(例如,这种方式更加灵活。)
function mapSomething() {
return Promise.all(_.map(someArray, function(item) {
return dosomething(item.foo).then(function (account) {
item.email = account.email;
});
})
}
mapSomething.then(mapSucessHandler, mapErrorHandler);
我自己没有尝试过Bluebird的.map()
,但是一旦你宣传了数据库调用,我认为它会更简化它:
function mapSomething() {
return Promise.map(someArray, function(item) {
return dosomething(item.foo).then(function (account) {
item.email = account.email;
});
})
}
mapSomething.then(mapSucessHandler, mapErrorHandler);