跟踪完成的JavaScriptcallback没有嵌套function

所以我正在写一个函数,使一堆数据库调用。 我想将它们的结果存储在一个数组中,并在完成之后触发一个callback。

一些伪代码可能会有所帮助:

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); }); } } 

这很好。 不过,我被告知,在循环中嵌套一个闭包是一个不好的习惯,因为它每次迭代都会定义函数,而且会带来性能上的代价。

其他答案build议将callback移到循环之外:

 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有一个不可变的types,所以它不会改变getStuff的值。

那么…我该怎么办?

您可以只定义一次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)); } } 

这是一个使用Q和promise的解决scheme

首先,用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 }); } 

在我看来,这是一个更优雅的解决scheme,我build议您阅读Q及其所有可能的用法,它可以避免您有很多嵌套callback(通常称为“callback地狱”)的恶劣情况。