先来看个需求,页面上有2个ajax call。其中一个ajax需要另一个ajax的数据才能操作。如下面这段代码所描述的
0102030405060708091011121314151617 | $( function (){ var a_data; $.ajax({ url: "test.php" , success: function (data){ a_data = data; }, }); $.ajax({ url: "test.php" , success: function (data){ if (a_data == "5" ){ //.... } }, }); }); |
第二个ajax的操作,需要等待第一个ajax的数据才能进行。(ps:当然以上写法是错误的,这里只是描述这个需求)
相信不少人都遇到ajax queue队列的问题。好在自从jquery 1.3 以后,有个function能够很好的支持队列,那就是queue
。
queue(name)
返回指向第一个匹配元素的队列(将是一个函数数组)
要实现ajax队列,可以将ajax引入queue中。如下代码实现
01020304050607080910111213141516171819202122 | // 第一个ajax请求 $(document).queue( "ajaxRequests" , function (){ //全局变量,储存第一个ajax请求数据 var a_data; $.ajax({ success: function (data){ a_data = data; $(document).dequeue( "myName" ); } }); }); // 第二个ajax请求 $(document).queue( "ajaxRequests" , function () { $.ajax({ success: function (data) { alert(a_data); $(document).dequeue( "myName" ); } }); }); // 触发queue往下执行 $(document).dequeue( "ajaxRequests" ); |
以上代码实现了ajax队列,2个ajax同步执行,其中dequeue用来结束当前ajax,并调用下一个ajax请求。
接下来,我们再来看看另一个ajax 队列的需求(需求二):
在注册的时候验证邮箱、用户名等时候,单个客户端可以频繁发出无数的ajax请求出去,而我们的结果肯定是以最后一个ajax请求为准的。
首先模拟一个服务端页面:
1234 | <?PHP sleep(5); exit (time(). '' ); ?> |
然后是前台页面,假设由一个元素触发:
html代码:
010203040506070809101112 | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> < html xmlns = "http://www.w3.org/1999/xhtml" > < head > < meta http-equiv = "Content-Type" content = "text/html;charset=utf-8" /> < title >测试ajax队列</ title > </ head > < body > < div id = "dtitle" >点此触发</ div > </ body > < script type = "text/javascript" src = "http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js" ></ script > < script type = "text/javascript" src = "test.js" ></ script > </ html > |
JS代码:
01020304050607080910111213 | $( function (){ $( "body" ).queue([]); $( "#dtitle" ).click( function (){ $( "body" ).queue( function (){ $.get( "test.php?t=" + new Date().getMilliseconds(), function (){ //这一句让queue往下执行; $( "body" ).dequeue(); if ($( "body" ).queue().length == 0) alert( "done" ); }); }); }); }); |
下面是firebug下的执行结果,我连续对dtitle元素点击三次,如愿每5秒才发送一次请求。当然这只是演示的原理,既然发了三次请求,肯定要以最后一次为准,那么可以通过队列的length属性来轮循,一时length变为0了,就是全部请求结束了,你就可以执行你想要的逻辑了
好了,通过上面的代码,应该对queue的用法和ajax队列有一定了解了。人总是要不断追求完美的,粗矿的代码,并不能提升代码水平。既然队列那么常用,那是否需要将这个功能封装?答案是肯定的。网上也有一些已经封装好了的插件。
那就重写$.ajax 这个方法吧。说干就干:
01020304050607080910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667 | ( function ($) { var ajax = $.ajax, pendingRequests = {}, synced = [], syncedData = [], ajaxRunning = []; $.ajax = function (settings) { // create settings for compatibility with ajaxSetup settings = jQuery.extend(settings, jQuery.extend({}, jQuery.ajaxSettings, settings)); var port = settings.port; switch (settings.mode) { case "abort" : if (pendingRequests[port]) { pendingRequests[port].abort(); } return pendingRequests[port] = ajax.apply( this , arguments); case "queue" : var _old = settings.complete; settings.complete = function () { if (_old) { _old.apply( this , arguments); } if (jQuery([ajax]).queue( "ajax" + port).length > 0) { jQuery([ajax]).dequeue( "ajax" + port); } else { ajaxRunning[port] = false ; } }; jQuery([ajax]).queue( "ajax" + port, function () { ajax(settings); }); if (jQuery([ajax]).queue( "ajax" + port).length == 1 && !ajaxRunning[port]) { ajaxRunning[port] = true ; jQuery([ajax]).dequeue( "ajax" + port); } return ; case "sync" : var pos = synced.length; synced[pos] = { error: settings.error, success: settings.success, complete: settings.complete, done: false }; syncedData[pos] = { error: [], success: [], complete: [] }; settings.error = function () { syncedData[pos].error = arguments; }; settings.success = function () { syncedData[pos].success = arguments; }; settings.complete = function () { syncedData[pos].complete = arguments; synced[pos].done = true ; if (pos == 0 || !synced[pos - 1]) for ( var i = pos; i < synced.length && synced[i].done; i++) { if (synced[i].error) synced[i].error.apply(jQuery, syncedData[i].error); if (synced[i].success) synced[i].success.apply(jQuery, syncedData[i].success); if (synced[i].complete) synced[i].complete.apply(jQuery, syncedData[i].complete); synced[i] = null ; syncedData[i] = null ; } }; } return ajax.apply( this , arguments); }; })(jQuery); |
以上代码加入了1个mode变量,有3个值”abort”(中止),”queue”(队列),”sync”同步。
对于需求二,我们用这个封装好的ajax改写并改进下,js代码部分如下:
0102030405060708091011121314 | $( function (){ $( "body" ).queue([]); $( "#dtitle" ).click( function (){ $.ajax({ url: "test.php?t=" + new Date().getMilliseconds(), success: function (html){ jQuery( "ul" ).append(html); }, //用abort而不用queue,是因为需求是需要最后一个ajax request,而之前的ajax request //其实并没有用,那何必要等它们执行完呢?中途就可以把它中止掉 mode: "abort" }); }); }); |
看到这里,相信你已经完全了解ajax队列了。就算不了解,你也可以直接用封装好的那段js代码,直接用mode: “abort”
就可以了。