sortingajax请求
我发现我有时需要迭代一些集合,并为每个元素做一个Ajax调用。 我希望每个调用在返回到下一个元素之前都要返回,这样我就不会用请求来爆炸服务器 – 这往往会导致其他问题。 我不想将asynchronous设置为false并冻结浏览器。
通常这涉及到设置某种迭代器上下文,我通过每个成功callback。 我认为必须有一个更简单的方法?
有没有人有一个聪明的devise模式,如何整齐地工作,通过一个集合使每个项目的Ajax调用?
jQuery 1.5+
我开发了一个$.ajaxQueue()
插件,它使用$.Deferred
, .queue()
和$.ajax()
来传递一个在请求完成时parsing的promise 。
/* * jQuery.ajaxQueue - A queue for ajax requests * * (c) 2011 Corey Frang * Dual licensed under the MIT and GPL licenses. * * Requires jQuery 1.5+ */ (function($) { // jQuery on an empty object, we are going to use this as our Queue var ajaxQueue = $({}); $.ajaxQueue = function( ajaxOpts ) { var jqXHR, dfd = $.Deferred(), promise = dfd.promise(); // queue our ajax request ajaxQueue.queue( doRequest ); // add the abort method promise.abort = function( statusText ) { // proxy abort to the jqXHR if it is active if ( jqXHR ) { return jqXHR.abort( statusText ); } // if there wasn't already a jqXHR we need to remove from queue var queue = ajaxQueue.queue(), index = $.inArray( doRequest, queue ); if ( index > -1 ) { queue.splice( index, 1 ); } // and then reject the deferred dfd.rejectWith( ajaxOpts.context || ajaxOpts, [ promise, statusText, "" ] ); return promise; }; // run the actual query function doRequest( next ) { jqXHR = $.ajax( ajaxOpts ) .done( dfd.resolve ) .fail( dfd.reject ) .then( next, next ); } return promise; }; })(jQuery);
jQuery 1.4
如果您使用的是jQuery 1.4,则可以使用空对象上的animation队列为您的ajax元素请求创build自己的“队列”。
你甚至可以把它分解成你自己的$.ajax()
replace。 这个插件$.ajaxQueue()
为jQuery使用了标准的“fx”队列,如果队列还没有运行的话,它将自动启动第一个添加的元素。
(function($) { // jQuery on an empty object, we are going to use this as our Queue var ajaxQueue = $({}); $.ajaxQueue = function(ajaxOpts) { // hold the original complete function var oldComplete = ajaxOpts.complete; // queue our ajax request ajaxQueue.queue(function(next) { // create a complete callback to fire the next event in the queue ajaxOpts.complete = function() { // fire the original complete if it was there if (oldComplete) oldComplete.apply(this, arguments); next(); // run the next query in the queue }; // run the query $.ajax(ajaxOpts); }); }; })(jQuery);
用法示例
所以,我们有一个<ul id="items">
,它有一些<li>
我们想要复制(使用ajax!)到<ul id="output">
// get each item we want to copy $("#items li").each(function(idx) { // queue up an ajax request $.ajaxQueue({ url: '/echo/html/', data: {html : "["+idx+"] "+$(this).html()}, type: 'POST', success: function(data) { // Write to #output $("#output").append($("<li>", { html: data })); } }); });
jsfiddle演示 – 1.4版本
使用延期承诺的快速小解决scheme。 虽然这使用jQuery的$.Deferred
,任何其他应该做的。
var Queue = function () { var previous = new $.Deferred().resolve(); return function (fn, fail) { return previous = previous.then(fn, fail || fn); }; };
用法,调用来创build新的队列:
var queue = Queue(); // Queue empty, will start immediately queue(function () { return $.get('/first'); }); // Will begin when the first has finished queue(function() { return $.get('/second'); });
请参阅示例 ,并排比较asynchronous请求。
你可以把所有这些复杂的东西包装到一个函数中来做一个简单的调用,如下所示:
loadSequantially(['/a', '/a/b', 'a/b/c'], function() {alert('all loaded')});
下面是一个粗略的草图(工作示例,除了ajax调用)。 这可以修改为使用类似队列的结构而不是数组
// load sequentially the given array of URLs and call 'funCallback' when all's done function loadSequantially(arrUrls, funCallback) { var idx = 0; // callback function that is called when individual ajax call is done // internally calls next ajax URL in the sequence, or if there aren't any left, // calls the final user specified callback function var individualLoadCallback = function() { if(++idx >= arrUrls.length) { doCallback(arrUrls, funCallback); }else { loadInternal(); } }; // makes the ajax call var loadInternal = function() { if(arrUrls.length > 0) { ajaxCall(arrUrls[idx], individualLoadCallback); }else { doCallback(arrUrls, funCallback); } }; loadInternal(); }; // dummy function replace with actual ajax call function ajaxCall(url, funCallBack) { alert(url) funCallBack(); }; // final callback when everything's loaded function doCallback(arrUrls, func) { try { func(); }catch(err) { // handle errors } };
理想情况下,一个有多个入口点的协同程序,所以从服务器的每个callback都可以调用相同的协程。 该死的,这个即将在Javascript 1.7中实现。
让我尝试使用闭包…
function BlockingAjaxCall (URL,arr,AjaxCall,OriginalCallBack) { var nextindex = function() { var i =0; return function() { return i++; } }; var AjaxCallRecursive = function(){ var currentindex = nextindex(); AjaxCall ( URL, arr[currentindex], function() { OriginalCallBack(); if (currentindex < arr.length) { AjaxCallRecursive(); } } ); }; AjaxCallRecursive(); } // suppose you always call Ajax like AjaxCall(URL,element,callback) you will do it this way BlockingAjaxCall(URL,myArray,AjaxCall,CallBack);
是的,而其他答案将工作,他们是很多的代码和杂乱的样子。 Frame.js旨在优雅地解决这种情况。 bishopZ/Frame.html
例如,这会导致大多数浏览器挂起:
for(var i=0; i<1000; i++){ $.ajax('myserver.api', { data:i, type:'post' }); }
虽然这不会:
for(var i=0; i<1000; i++){ Frame(function(callback){ $.ajax('myserver.api', { data:i, type:'post', complete:callback }); }); } Frame.start();
此外,使用框架允许您瀑布的响应对象,并处理所有完整的一系列AJAX请求后(如果你想):
var listOfAjaxObjects = [ {}, {}, ... ]; // an array of objects for $.ajax $.each(listOfAjaxObjects, function(i, item){ Frame(function(nextFrame){ item.complete = function(response){ // do stuff with this response or wait until end nextFrame(response); // ajax response objects will waterfall to the next Frame() $.ajax(item); }); }); Frame(function(callback){ // runs after all the AJAX requests have returned var ajaxResponses = []; $.each(arguments, function(i, arg){ if(i!==0){ // the first argument is always the callback function ajaxResponses.push(arg); } }); // do stuff with the responses from your AJAX requests // if an AJAX request returned an error, the error object will be present in place of the response object callback(); }); Frame.start()
我使用http://developer.yahoo.com/yui/3/io/#queue获取该function。;
我所能想出的唯一解决scheme就是,如您所说,维护待处理的调用/callback列表。 或者在之前的callback中embedded下一个呼叫,但是这感觉有点混乱。
那么你可以用同样的东西来实现。
var files = [ 'example.txt', 'example2.txt', 'example.txt', 'example2.txt', 'example.txt', 'example2.txt', 'example2.txt', 'example.txt' ]; nextFile().done(function(){ console.log("done",arguments) }); function nextFile(text){ var file = files.shift(); if(text) $('body').append(text + '<br/>'); if(file) return $.get(file).then(nextFile); }
现在也可以使用ES6中引入的本地承诺支持。 您可以将ajax调用包装在一个承诺中,并将其返回给元素的处理程序。
function ajaxPromise(elInfo) { return new Promise(function (resolve, reject) { //Do anything as desired with the elInfo passed as parameter $.ajax({ type: "POST", url: '/someurl/', data: {data: "somedata" + elInfo}, success: function (data) { //Do anything as desired with the data received from the server, //and then resolve the promise resolve(); }, error: function (err) { reject(err); }, async: true }); }); }
现在recursion地调用函数,从你有元素集合的地方开始。
function callAjaxSynchronous(elCollection) { if (elCollection.length > 0) { var el = elCollection.shift(); ajaxPromise(el) .then(function () { callAjaxSynchronous(elCollection); }) .catch(function (err) { //Abort further ajax calls/continue with the rest //callAjaxSynchronous(elCollection); }); } else { return false; } }