jQuery实现的ajax队列(queue)

先来看个需求,页面上有2个ajax call。其中一个ajax需要另一个ajax的数据才能操作。如下面这段代码所描述的

帮助
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
$( 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中。如下代码实现

帮助
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
// 第一个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请求为准的。
首先模拟一个服务端页面:

帮助
1
2
3
4
     sleep(5);
     exit (time(). '' );
?>

然后是前台页面,假设由一个元素触发:
html代码:

帮助
01
02
03
04
05
06
07
08
09
10
11
12
< 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代码:

帮助
01
02
03
04
05
06
07
08
09
10
11
12
13
$( 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 这个方法吧。说干就干:

帮助
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
( 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代码部分如下:

帮助
01
02
03
04
05
06
07
08
09
10
11
12
13
14
$( 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”
就可以了。

你可能感兴趣的:(JavaScript)