原代码是使用一个循环执行批量的$.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 {
//完成//
}
};
黄舟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) {
// 处理异常
}
});
巴扎黑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);
高洛峰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 查看。
怪我咯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();
PHPz2017-04-10 12:48:14
但是不管怎么说,该发多少个请求还是得发多少个请求啊。要想降低发送的请求数量,必须把多个请求组合在一起发送。这需要后端提供一个新的支持批量请求的(比如说接收一个json的array,里面装有单个请求的数据)API。
然后在前端也可以写一个请求收集器,将一小段时间内发送的单个请求打包成一个批量请求发送给服务器,这样原先的代码就不需要改动了。