How to set callback order invocation same as target function invocation

后端 未结 3 2050
谎友^
谎友^ 2021-01-29 10:33

I have a problem in my project.

To describe this issue I have wrote simplified code snippet:

function waitFor(fnReady, fnCallback) {
    var check = fun         


        
相关标签:
3条回答
  • 2021-01-29 10:50

    Try this pattern

    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/

    0 讨论(0)
  • 2021-01-29 10:53

    I personally would use promises for this, but you've said no promises (not sure why), so here's a generic sequencer algorithm in plain javascript (tested in the jsFiddle linked below):

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

    Working demo: http://jsfiddle.net/jfriend00/aqugm1fs/


    Conceptually, what this does is as follows:

    1. Pass a substitute completion handler in place of the normal completion callback.
    2. This substitute function marks each response with a sequence id and saved the original completion handler.
    3. If a response comes back while another response with a lower sequence id is still pending, then the result is just stored and saved for later.
    4. As each response comes in, it processes as many responses in sequence as are ready

    Note: while all the examples you have use the same callback function, this will work with any callback function so it would work with a mix of different types of operations.

    0 讨论(0)
  • 2021-01-29 10:58

    my variant:

    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/

    0 讨论(0)
提交回复
热议问题