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

时间:2014-11-01 20:13:47

标签: javascript jquery synchronization

我的项目有问题。

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

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方法向服务器发送请求,并在地图上成功替代渲染结果。但是这个事件经常发生

3 个答案:

答案 0 :(得分:0)

尝试这种模式

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/

答案 1 :(得分:0)

我个人会为此使用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. 当每个响应都出现时,它会按顺序处理尽可能多的响应
  5. 注意:虽然您使用相同的回调函数的所有示例,这将适用于任何回调函数,因此它可以使用不同类型的操作。

答案 2 :(得分:0)

我的变体:

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/