[英]determining the end of asynchronous operations javascript
如果我有一个传递了这个函数的函数:
function(work) {
work(10);
work(20);
work(30);
}
(可以有任意数量的work
电话,其中包含任何数字。)
work
性能一些异步活动 - 比如,对于这个例子,它只是一个timeout
。 我有过什么样的完全控制work
对这一操作的完成做(和,事实上,它的一般定义)。
确定何时完成所有work
呼叫的最佳方法是什么?
我的当前方法在调用工作时递增计数器,在完成时递减计数器,并在计数器为0时触发all work done
事件(在每次递减后检查)。 但是,我担心这可能是某种竞争条件。 如果情况并非如此,请展示我的原因,这将是一个很好的答案。
没有竞争条件。 每个请求在完成时执行减量的要求都增加了( 总是!包括http失败,很容易忘记)。 但是,可以通过包装调用以更封装的方式处理。
未经测试,但这是要点(我已经实现了一个对象而不是一个计数器,所以理论上你可以扩展它以获得关于特定请求的更细粒度的查询):
var ajaxWrapper = (function() {
var id = 0, calls = {};
return {
makeRequest: function() {
$.post.apply($, arguments); // for example
calls[id] = true;
return id++;
},
finishRequest: function(id) {
delete calls[id];
},
isAllDone: function(){
var prop;
for(prop in calls) {
if(calls.hasOwnProperty(prop)) {return false;}
}
return true;
}
};
})();
用法:
而不是$.post("url", ... function(){ /*success*/ } ... );
干的好
var requestId;
requestId = ajaxWrapper.makeRequest("url", ...
function(){ /*success*/ ajaxWrapper.finishRequest(requestId); } ... );
如果你想要更复杂,你可以在包装器中自己添加对finishRequest
的调用,因此使用几乎完全透明:
ajaxWrapper.makeRequest("url", ... function(){ /*success*/ } ... );
你有很多方法可以编写这个程序,但是你使用计数器的简单技巧就可以了。
重要的是要记住,这将起作用的原因是因为Javascript在单个线程中执行 。 所有浏览器和node.js AFAIK都是如此。
基于下面的深思熟虑的评论,解决方案可行,因为JS事件循环将按以下顺序执行函数:
我有一个after
效用函数。
var after = function _after(count, f) {
var c = 0, results = [];
return function _callback() {
switch (arguments.length) {
case 0: results.push(null); break;
case 1: results.push(arguments[0]); break;
default: results.push(Array.prototype.slice.call(arguments)); break;
}
if (++c === count) {
f.apply(this, results);
}
};
};
以下代码将起作用。 因为javascript是单线程的。
function doWork(work) {
work(10);
work(20);
work(30);
}
WorkHandler(doWork);
function WorkHandler(cb) {
var counter = 0,
finish;
cb(function _work(item) {
counter++;
// somethingAsync calls `finish` when it's finished
somethingAsync(item, function _cb() {
finish()
});
});
finish = after(counter, function() {
console.log('work finished');
});
};
我想我应该解释一下。
我们将有效的函数传递给workhandler。
工作处理程序调用它并传入工作。
执行工作的函数调用多次递增计数器
由于工作的函数不是异步的(非常重要),我们可以在完成后定义完成函数。
正在完成的异步工作无法在当前同步工作块(整个工作处理程序的执行)完成之前完成(并调用未定义的完成函数)。
这意味着在整个workhandler完成后(并且设置了变量finish),异步工作作业将开始结束并调用finish。 只有当所有人都呼叫完成after
,回调才会发送到火灾after
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.