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

How to set callback order invocation same as target function invocation

本文关键字:目标 函数调用 设置 回调 顺序调用      更新时间:2023-09-26

我的项目有问题。

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

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
--------------------
.....

你能帮我更正代码吗?

更新

实际问题:

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

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

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

jsfiddlehttp://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/

我个人会使用promise来实现这一点,但你说没有promise(不确定为什么),所以这里有一个普通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. 当每个响应到来时,它会按照准备好的顺序处理尽可能多的响应

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