所以我正在编写一个能够进行大量数据库调用的函数。我想将结果存储在数组中,并在完成后触发回调。
某些伪代码可能有所帮助:
function getStuff (array, callback) {
var results = [];
var done = 0;
for (var i = 0, len = array.length; i < len; i++) {
database.fetchOne(array[i], function(result) {
results[i] = result;
done++;
if (done == len)
callback(results);
});
}
}
这很有效。但是,我被告知在一个循环中嵌套一个闭包是不好的做法,因为它会在每次迭代时不断定义函数,并且会产生性能成本。
其他答案建议将回调移到循环之外:
function getStuff (array, callback) {
var results = [];
var done = 0;
for (var i = 0, len = array.length; i < len; i++) {
database.fetchOne(array[i], myCallback.bind(this, i, results, done, callback));
}
}
function myCallback (i, results, done, callback, result) {
results[i] = result;
done++;
if (done == len)
callback(results);
}
但是这不起作用,因为done
具有不可变类型,因此它不会更改done
中getStuff
的值。
那么......我该怎么做?
答案 0 :(得分:3)
您可以只定义一次myCallback,而不是每次迭代。
function getStuff (array, callback) {
var results = [];
var done = 0;
function myCallback(i, callback, result) {
// update results and done in here
}
for (var i = 0, len = array.length; i < len; i++) {
database.fetchOne(array[i], myCallback.bind(this, i, results, done, callback));
}
}
答案 1 :(得分:2)
这是使用带有Q的承诺的解决方案
首先,使用npm
安装Q.npm install q
记得要求它
var Q = require('q');
那么你的最终代码可能就是这个
function getStuff (array, callback) {
//denodeify transforms a node function into one that works with promises
var fetch = Q.denodeify(database.fetchOne);
// all waits for all promises to be resolved
var promise = Q.all(array.map(fetch));
// callback receives an array with all the return values from fetchOne
promise.then(callback, function(error) {
//this gets called in case any of the calls has an error
});
}
在我看来,这是一个更优雅的解决方案,我建议阅读Q及其所有可能的用法,它可以避免令人讨厌的情况,你有很多嵌套回调(通常被称为&#39;回调地狱&#39; )