跟踪 javascript 个没有嵌套函数的回调的完成情况
Track completion of javascript callbacks without nesting functions
所以我正在编写一个进行大量数据库调用的函数。我想将它们的结果存储在一个数组中,并在它们全部完成后触发回调。
一些伪代码可能会有所帮助:
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
具有不可变类型,因此它不会更改 getStuff
中 done
的值。
那么...我该怎么办?
您可以只定义一次 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));
}
}
这是一个使用 promise 和 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 及其所有可能的用法,它可以避免出现大量嵌套回调(通常称为 'callback hell')的讨厌情况
所以我正在编写一个进行大量数据库调用的函数。我想将它们的结果存储在一个数组中,并在它们全部完成后触发回调。
一些伪代码可能会有所帮助:
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
具有不可变类型,因此它不会更改 getStuff
中 done
的值。
那么...我该怎么办?
您可以只定义一次 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));
}
}
这是一个使用 promise 和 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 及其所有可能的用法,它可以避免出现大量嵌套回调(通常称为 'callback hell')的讨厌情况