在没有嵌套函数的情况下跟踪 javascript 回调的完成
Posted
技术标签:
【中文标题】在没有嵌套函数的情况下跟踪 javascript 回调的完成【英文标题】:Track completion of javascript callbacks without nesting functions 【发布时间】:2015-10-01 01:36:38 【问题描述】:所以我正在编写一个进行大量数据库调用的函数。我想将他们的结果存储在一个数组中,并在完成后触发回调。
一些伪代码可能会有所帮助:
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
的值。
那么……我该怎么办?
【问题讨论】:
澄清一下,done
不是不可变类型,它是一个通过值而不是通过引用传递的原语。这是一个很好的区别,但我认为需要注意这一点。
你在什么背景下?这是 node.js 吗?您可以通过使用承诺并在所有完成后执行回调来解决此问题,这应该是一种更优雅的处理方式。
@Sosdoc,没关系。在 node.js 和客户端 JS 中,异步回调的标准相同。
@PatrickRoberts 我只是要求指出一个使用 Promise 的可能解决方案,以防这不是节点(但我怀疑)它可以通过使用 jquery 来完成。
@Sosdoc 我在节点中。
【参考方案1】:
您可以只定义一次 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));
【讨论】:
如果我要使用这种方法,我也会亲自将results
全球化到闭包,而不是将其传递给每个函数。
那么当getStuff
在匿名函数内部时,我该如何调用它呢?
我实际上才意识到这只会让getStuff
工作一次。也许我的编辑不是那么优雅。
@PatrickRoberts 也许如果 done
和 results
在闭包中定义,但它们的值是在 getStuff
中设置的?
可能在 getStuff 中定义 myCallback、done 和 results,但不在循环中?【参考方案2】:
这是一个使用带 Q 的 Promise 的解决方案
首先,用 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 及其所有可能的用法,它可以避免出现大量嵌套回调(通常称为“回调地狱”)的恶劣情况
【讨论】:
绝对更优雅。稍后我会研究它,谢谢!以上是关于在没有嵌套函数的情况下跟踪 javascript 回调的完成的主要内容,如果未能解决你的问题,请参考以下文章
如何在没有外部递归函数的情况下解析多个嵌套的 JSON 键?
在没有 Javascript 的情况下使用 Google Analytics?