例如,我有两个并发的AJAX请求,我需要两者的结果来计算第三个结果。我正在使用Prototype库,所以它看起来像这样:
var r1 = new Ajax.Request(url1, ...);
var r2 = new Ajax.Request(url2, ...);
function on_both_requests_complete(resp1, resp2) {
...
}
一种方法是使用民意调查,但我认为必须有更好的方法。
更新:可接受的解决方案必须没有竞争条件。
答案 0 :(得分:1)
在每个请求的回调函数中,设置一个布尔值,如
request1Complete
和request2Complete
并致电on_both_requests_complete(resp1,resp2)
。
在处理程序函数中,检查是否设置了两个布尔值。如果没有,只需返回并退出该功能。回调函数应该被序列化,因为它们不能同时发生,所以这应该有效。如果它们可以并行发生,那么你就会在竞争条件下中断。
答案 1 :(得分:1)
我就是这样做的。该方法是一种通用方法,它为您提供了更多的灵活性和重用,并避免了全局变量的耦合和使用。
var makeEventHandler = function(eventMinimum, callback) {
var data = [];
var eventCount = 0;
var eventIndex = -1;
return function() {
// Create a local copy to avoid issues with closure in the inner-most function
var ei = ++eventIndex;
return function() {
// Convert arguments into an array
data[ei] = Array.prototype.slice.call(arguments);
// If the minimum event count has not be reached, return
if ( ++eventCount < eventMinimum ) {
return;
}
// The minimum event count has been reached, execute the original callback
callback(data);
};
};
};
一般用法:
// Make a multiple event handler that will wait for 3 events
var multipleEventHandler = makeMultipleEventHandler(3, function(data) {
// This is the callback that gets called after the third event
console.log(data);
});
multipleEventHandler()(1,2,3);
var t = multipleEventHandler();
setTimeout(function() {t("some string");}, 1000);
multipleEventHandler()({a: 4, b: 5, c: 6});
回调输出(由Firebug压缩):
[[1, 2, 3], ["some string"], [Object { a=4, more...}]]
请注意,最终回调中data
的顺序是按照调用事件的顺序,即使第二个“事件”在第三个之后执行。
在Ajax请求的上下文中使用它:
var onBothComplete = makeMultipleEventHandler(2, function(data) {
// Do something
...
});
new Ajax.Request(url1, {onComplete: onBothComplete()});
new Ajax.Request(url2, {onComplete: onBothComplete()});
编辑:我已更新该函数以强制data
始终以同步执行的顺序维护异步接收的事件数据(之前的警告不再存在)。
答案 2 :(得分:0)
嗯,你必须记住,浏览器中的JS实现并不是真正的并发,并且使用它对您有利。所以你想要做的就是在每个处理程序中检查对方是否已完成。 jQuery中的示例:
var other_done = false;
$.get('/one', function() {
if (other_done) both_completed();
other_done = true;
alert('One!');
});
$.get('/two', function() {
if (other_done) both_completed();
other_done = true;
alert('Two!');
});
function both_completed() {
alert('Both!');
}
答案 3 :(得分:0)
您可以使用设置临时变量的概念并等待“最后”请求。为此,您可以让两个句柄函数将tmp变量设置为返回值,然后调用“on_both_requests_complete”函数。
var processed = false;
var r1 = new Ajax.Request(...);
var r2 = new Ajax.Request(...);
(function() {
var data1;
var data2;
function handle_r1(data) {
data1 = data;
on_both_requests_complete();
};
function handle_r2(data) {
data2 = data;
on_both_requests_complete();
};
function on_both_requests_complete() {
if ( (!data1 || !data2) || processed) {
return;
}
processed = true;
/* do something */
};
}();
答案 4 :(得分:0)
基于Justin Johnson's response to this question:
function sync(delays /* Array of Functions */, on_complete /* Function */) {
var complete_count = 0;
var results = new Array(delays.length);
delays.length.times(function (i) {
function on_progress(result) {
results[i] = result;
if (++complete_count == delays.length) {
on_complete(results);
}
}
delays[i](on_progress);
});
}
这假设每个延迟都接受一个参数:一个“on progress”事件处理程序,它接受一个参数:延迟试图计算的结果。要完成原始问题中的示例,您可以这样使用它:
var delays = [];
delays[0] = function (on_progress) {
new Ajax.Request(url1, {onSuccess: on_progress});
};
delays[1] = function (on_progress) {
new Ajax.Request(url2, {onSuccess: on_progress});
};
function on_complete(results) { alert(results.inspect()); }
sync(delays, on_complete);
我不确定的一件事是这是否可以避免竞争条件。如果表达式++ complete_count == delays.length总是以原子方式发生,那么这应该可行。