代码之家  ›  专栏  ›  技术社区  ›  SBUJOLD

在一系列异步XHR调用之后添加“回调”的最佳方法

  •  1
  • SBUJOLD  · 技术社区  · 16 年前

    $(search).each(function() {
     $.ajax({
      url: 'save.x3?id='+$(this).attr("id")+'value='$(this).data("value");
      success: function(o){
       //Update UI
      },
      error: function(o){
       //Update UI
      }
     });
    });
    
    //code to do after saving...
    

    显然,“保存后要执行的代码…”通常在所有请求完成之前执行。在理想情况下,我希望服务器端代码一次处理所有请求,并在保存成功回调后移动//代码,但假设这不可能,我将代码更改为类似这样的代码,以确保在继续之前返回所有请求,我仍然不喜欢这些请求:

    var recs = [];
    $(search).each(function() {
     recs[recs.length] = 'save.x3?id='+$(this).attr("id")+'value='$(this).data("value");
    });
    
    var counter = 0;
    function saveRecords(){
     $.ajax({
      url: recs[counter],
      success: function(o){
       //Update progress
       if (counter<recs.length){
        counter++;
        saveRecords();
       }else{
        doneSavingRecords();
       }
      },
      error: function(o){
       //Update progress
       doneSavingRecords(o.status);
      }
     });
    }
    
    function doneSavingRecords(text){
     //code to do after saving...
    }
    
    if (recs.length>0){
     saveRecords();  //will recursively callback itself until a failed request or until all records were saved
    }else{
     doneSavingRecords();
    }
    

    因此,我正在寻找一种“最佳”方法,向一系列异步调用添加一点同步功能?

    谢谢

    4 回复  |  直到 16 年前
        1
  •  2
  •   Doug Neiner    16 年前

    更好的答案 :

    function saveRecords(callback, errorCallback){
      $('<div></div>').ajaxStop(function(){
        $(this).remove(); // Keep future AJAX events from effecting this
        callback();
      }).ajaxError(function(e, xhr, options, err){
        errorCallback(e, xhr, options, err);
      });
    
      $(search).each(function() {
        $.get('save.x3', { id: $(this).attr("id"), value: $(this).data("value") });
      });
    }
    

    saveRecords(function(){
       // Complete will fire after all requests have completed with a success or error
    }, function(e, xhr, options, err){
       // Error will fire for every error
    });
    

    原始答案 :如果它们需要按特定顺序排列,或者页面上有其他常规AJAX事件会影响 ajaxStop ,但速度会慢一些:

    function saveRecords(callback){
      var recs = $(search).map(function(i, obj) {
       return { id: $(obj).attr("id"), value: $(obj).data("value") };
      });
    
      var save = function(){
       if(!recs.length) return callback();
    
       $.ajax({
        url: 'save.x3',
        data: recs.shift(), // shift removes/returns the first item in an array
        success: function(o){
         save();
        },
        error: function(o){
         //Update progress
         callback(o.status);
        }
       });
      }
    
      save();
    }
    

    然后你可以这样称呼它:

    saveRecords(function(error){
       // This function will run on error or after all 
       // commands have run
    });
    
        2
  •  1
  •   Drew Wills    16 年前

    $.ajaxStop() 为此目的。

        3
  •  1
  •   Aaron Martins    13 年前

        //a list of URLs for which we'll make async requests
        var queue = ['/something.json', '/another.json']; 
    
        //will contain our return data so we can work with it
        //in our final unified callback ('displayAll' in this example)
        var data = [];
    
        //work through the queue, dispatch requests, check if complete
        function processQueue( queue ){
            for(var i = 0; i < queue.length; i++){
                $.getJSON( queue[i], function( returnData ) {
                    data.push(returnData);
    
                    //reduce the length of queue by 1
                    //don't care what URL is discarded, only that length is -1
                    queue.pop();
    
                    checkIfLast(displayAll(data));
                }).fail(function() {
                    throw new Error("Unable to fetch resource: " + queue[i]);
                });
            }
        }
    
        //see if this is last successful AJAX (when queue == 0 it is last)
        //if this is the last success, run the callback
        //otherwise don't do anything
        function checkIfLast(callback){
            if(queue.length == 0){
                callback();
            }
        }
    
        //when all the things are done
        function displayAll(things){
            console.log(things); //show all data after final ajax request has completed.
        }
    
        //begin
        processQueue();
    

    编辑:我应该补充一点,我专门针对队列中任意数量的项目。您可以简单地添加另一个URL,这将同样有效。

        4
  •  0
  •   Geoff Moller    16 年前

    >>

    Closure的net.BulkLoader(或类似的方法)将为您提供:

    见: goog.net.BulkLoader.prototype.handleSuccess(用于单独调用) goog.net.BulkLoader.prototype.finishLoad(用于完成所有调用)