如何设置与目标函数调用相同的回调顺序调用

我的项目有问题。

为了描述这个问题,我编写了简化的代码片段:

function waitFor(fnReady, fnCallback) { var check = function() { if (fnReady()) { fnCallback(); } else { setTimeout(check, 100); // wait another 100ms, and try again } }; check(); } var result = 0; var flag = true; function ajaxRequest() { setTimeout( function() { flag = false; console.log('ping'); },3000 ); } function ajaxRequestHandler() { setTimeout( function() { flag = true; console.log('pong'); }, 200 ); } for(var i =0;i<10; i++){ waitFor(function() { return flag; }, ajaxRequest); waitFor(function() { return !flag; }, ajaxRequestHandler); } 

它返回:

 ping - 10 times pong - 10 times 

期望的结果:

 ping 3 second timeout ping --------------------- ping 3 second timeout pong -------------------- ..... 

你能帮忙纠正我的代码吗?

UPDATE

实际问题:

我有谷歌地图。
我应该重新绘制它时有很多地方。

对于应用程序逻辑非常重要,如果我发送

 request1 request2 request3 request4 

我应该按照这个顺序处理回复

 handle response of request1 handle response of request2 handle response of request3 handle response of request4 

我不知道请求顺序的问题。

在文件的不同位置,我看到以下代码行:

 google.maps.event.addListener(searchBox, 'bounds_changed', renderTerminalsOnMapAndFitBounds); ... $.getJSON('getAllTerminals.json', renderTerminalsOnMapAndFitBounds); ..... $.getJSON('getAllTerminalsInsideRectangle.json', renderTerminalsOnMapAndFitBounds); ... $.getJSON('getAllTerminalsInsideCircle.json', renderTerminalsOnMapAndFitBounds); ... $.getJSON('getBigTerminals.json', renderTerminalsOnMapAndFitBounds); ........ 

renderTerminalsOnMapAndFitBounds方法向服务器发送请求,并在映射中成功替代渲染结果。 但这件事经常发生

尝试这种模式

 var map = "abcdefghi".split(""); var responses = []; // collect responses $.ajaxSetup({ beforeSend : function(jqxhr, settings) { jqxhr.id = Number(settings.data.split(/id=/)[1]); // add `id` to `request` console.log(settings.data.split(/id=/)[1]); } }); var request = function(id, data) { // append `id` to `id` data return $.post("/echo/json/", {json:JSON.stringify([data]), id:id}) }; $.each(map, function(k, v) { setTimeout(function() { request(k + 1, v) .done(function(data) { // do stuff at each response console.log(data); // note return values }) .always(function(data, textStatus, jqxhr) { // do stuff at each response responses.push([jqxhr.id, data[0]]); // do stuff when all requests completed , results items in `responses` if (responses.length === map.length) { responses.sort(); // sort `responses` based on `id` // do stuff with `responses` console.log(responses); } }); },1 + Math.random() * 1000) // async }); 

jsfiddle http://jsfiddle.net/guest271314/g254bbjg/

我的变种:

 var index = 0; // callback function function tryMe (param1) { waitFor(function(){return param1 == index}, function(){console.log(param1); index++; } ) } // callback executer function callbackTester (callback,i) { setTimeout( function(){callback(i);}, 20000 - i*1000); } // test function for(var i=0 ; i<10 ; i++){ callbackTester ( tryMe,i ); } function waitFor(fnReady, fnCallback) { var check = function() { if (fnReady()) { fnCallback(); } else { setTimeout(check, 100); // wait another 100ms, and try again } }; check(); } 

http://jsfiddle.net/x061dx75/17/

我个人会为此使用promises,但你没有声明(不确定原因),所以这里是普通的javascript中的通用音序器算法(在下面链接的jsFiddle中测试):

 function sequence(fn) { // initialize sequence data upon first use if (typeof sequence.low === "undefined") { sequence.low = sequence.high = 0; sequence.results = {}; } // save id in local variable so we can reference it in the closure from the function below var id = sequence.high; // advance to next sequence number ++sequence.high; // initialize the result value for this sequence callback sequence.results[id] = {fn: fn, args: [], ready: false, context: null}; return function(/* args */) { // save args and context and mark it ready var args = Array.prototype.slice.call(arguments, 0); // get the results object for this callback and save info in it var thisResult = sequence.results[id]; thisResult.args = args; thisResult.context = this; thisResult.ready = true; // now process any requests in order that are ready for (var i = sequence.low; i < sequence.high; i++) { var result = sequence.results[i]; // if this one is ready, process it if (result.ready) { // increment counter past this result ++sequence.low; // remove this stored result delete sequence.results[i]; // process this result result.fn.apply(result.context, result.args); } else { // if this one not ready, then nothing to do yet break; } } }; } // your usage: google.maps.event.addListener(searchBox, 'bounds_changed', sequence(renderTerminalsOnMapAndFitBounds)); ... $.getJSON('getAllTerminals.json', sequence(renderTerminalsOnMapAndFitBounds)); ..... $.getJSON('getAllTerminalsInsideRectangle.json', sequence(renderTerminalsOnMapAndFitBounds)); ... $.getJSON('getAllTerminalsInsideCircle.json', sequence(renderTerminalsOnMapAndFitBounds)); ... $.getJSON('getBigTerminals.json', sequence(renderTerminalsOnMapAndFitBounds)); ........ 

工作演示: http : //jsfiddle.net/jfriend00/aqugm1fs/


从概念上讲,这样做的内容如下:

  1. 传递替代完成处理程序代替正常完成回调。
  2. 此替换函数使用序列ID标记每个响应并保存原始完成处理程序。
  3. 如果响应返回,而具有较低序列ID的另一个响应仍处于暂挂状态,则结果将被存储并保存以供日后使用。
  4. 当每个响应进入时,它会按顺序处理尽可能多的响应

注意:虽然您使用相同的回调函数的所有示例,这将适用于任何回调函数,因此它可以与不同类型的操作混合使用。