search

Home  >  Q&A  >  body text

javascript - 能否使用Jquery优化大量Ajax循环操作?

原代码是使用一个循环执行批量的$.get操作,如果使用单一循环过大,会瞬间对服务器做成大量请求。

for (i = 1; i < n; i++) {
    $.get("http://xxx/" + i,
    function(data) {
        do other..
    })
}

如果可以实现能否使用jQuery的Deferred Object进行代码的优化?把当完成一个get后再执行另外一个?令代码更有可读性?现在我用的办法是这样子:

    var url = new Array();
    for (i = 1; i < n; i++) {
        url.push("http://xxx/" + i)
    }
    var doGet = function() {
        if (url.length > 0) {
            var tmpimg = url.shift();
            $.get(tmpimg,
            function(data) {
                setTimeout(function() {
                    doGet()
                },
                500); //延时执行
            })
        } else {
            //完成//
        }
    };
PHP中文网PHP中文网2817 days ago581

reply all(6)I'll reply

  • 黄舟

    黄舟2017-04-10 12:48:14

    属于流程控制问题。

    可以借鉴很多 Flow Control 的库类来协助完成该功能。例如 wind.js, async 等。

    使用这些的好处是可以更方便地处理异常。楼上的递归方法很好的解决了问题,但是如果出现异常,就不方便处理了。

    花了几分钟自己裸写了一个,供参考。推荐去学习 wind.js , async 的实现(我还没看过 -_- )。

    这个的优点是统一异常的处理。代码的层级可能会少一些。

    var series = function (arr, iterator, callback) {
    
      var queues = [];
    
      var next = function (err) {
        if (err) {
          callback(err);
          return;
        }
        if(queues.length == 0) {
          callback();
          return;
        }
        queues.shift()(next);
      };
    
      var curry = function (func) {
        var args = [].slice.call(arguments);
        args.shift();
    
        return function () {
          args.concat([].slice.call(arguments));
          func.apply(func, args);
        }
      };
    
      for (var i = 0, n = arr.length; i < n; i++) {
        queues.push(curry(iterator, arr[i]));
      }
    
      next();
    };
    
    var urls = [];
    for (var i = 1; i < n; i++) {
      urls.push("http://xxx/" + i)
    }
    
    series(urls, function(url, next) {
      $.get(url, function(data) {
        // 随便做啥
    
        if(success) {
          // 如果没有任何问题
          next(null)
        } else {
          // 如果发生了某些错误
          var err = new Error();
          next(err);
        }
      })
    }, function(err) {
      if(err) {
        // 处理异常
    
      }
    });
    

    reply
    0
  • 巴扎黑

    巴扎黑2017-04-10 12:48:14

    使用 jQuery.ajax() , 设置 async 为 false

    for (i = 1; i < n; i++) {
        $.ajax({
          url: "http://xxx/" + i,
          async: false
        });
    
        ///do other..
    
    }
    

    JS 是单线程的,所以非常不推荐这种写法,会导致其它的任务被阻塞掉。推荐使用递归的方式使用

    function doSomething(i){
        $.get("http://xxx/" + i, function(data) {
            //do other..
            if(i<n){
                //递归
                doSomething(i+1);
            }
        })
    }
    
    //递归入口调用
    doSomething(0);
    
    

    reply
    0
  • 高洛峰

    高洛峰2017-04-10 12:48:14

    我这里写了一个顺序循环调用异步函数数组的方法,希望对你有帮助。
    要求: 你的函数必须返回jQuery Deferred 对象。

    // test methods fun1 and fun2 for test
    var fun1 = function () {
        var deferred = $.Deferred();
    
        setTimeout(function () {
            console.log('I am fun1');
        }, 1000);
    
        return deferred.resolve();
    }
    
    var fun2 = function () {
        var deferred = $.Deferred();
    
        setTimeout(function () {
            console.log('I am fun2');
        }, 1000);
    
        return deferred.resolve();
    }
    
    // make test jQuery asynchronous methods array
    var arr = [fun1, fun2];
    
    // This the target method for implementing that call jQuery asyn methods recursively
    var recursive = function(i, arr) {
        return execute(arr[i]).then(function() {
            if (i + 1 < arr.length) {
                recursive(i + 1, arr);
            }
        });
    
        function execute(func) {
            return func();
        }
    }
    
    // run our test
    recursive(0, arr);
    

    也可以访问我的Gist 查看。

    reply
    0
  • 怪我咯

    怪我咯2017-04-10 12:48:14

    var url = new Array();
        for (i = 1; i < n; i++) {
            url.push("http://xxx/" + i)
        }
    var doGet = function() {
        if (url.length > 0) {
            var tmpimg = url.shift();
            $.get(tmpimg,
            function(data) {
                //setTimeout(function() {
                //    doGet()
                //},
                //500); 延时执行
                //这个时候请求已经完成,不用延时,可以直接进行下一个请求
                doGet()
            })
        } else {
            //完成//
        }
    };
    doGet();
    

    reply
    0
  • PHPz

    PHPz2017-04-10 12:48:14

    但是不管怎么说,该发多少个请求还是得发多少个请求啊。要想降低发送的请求数量,必须把多个请求组合在一起发送。这需要后端提供一个新的支持批量请求的(比如说接收一个json的array,里面装有单个请求的数据)API。

    然后在前端也可以写一个请求收集器,将一小段时间内发送的单个请求打包成一个批量请求发送给服务器,这样原先的代码就不需要改动了。

    reply
    0
  • 阿神

    阿神2017-04-10 12:48:14

    楼上正解,想减少服务器负荷,合并请求才是王道.

    reply
    0
  • Cancelreply