jQuery实现的ajax队列(queue)

时间:2021-03-19 17:40:56

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

帮助
0102030405060708091011121314151617 $(function(){    vara_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请求数据    vara_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"><htmlxmlns="http://www.w3.org/1999/xhtml">    <head>        <metahttp-equiv="Content-Type"content="text/html;charset=utf-8"/>        <title>测试ajax队列</title>    </head><body>    <divid="dtitle">点此触发</div></body><scripttype="text/javascript"src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script><scripttype="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了,就是全部请求结束了,你就可以执行你想要的逻辑了
jQuery实现的ajax队列(queue)

好了,通过上面的代码,应该对queue的用法和ajax队列有一定了解了。人总是要不断追求完美的,粗矿的代码,并不能提升代码水平。既然队列那么常用,那是否需要将这个功能封装?答案是肯定的。网上也有一些已经封装好了的插件。
那就重写$.ajax 这个方法吧。说干就干:

帮助
01020304050607080910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667 (function($) {    varajax = $.ajax,        pendingRequests = {},        synced = [],        syncedData = [],        ajaxRunning = [];    $.ajax =function(settings) {        // create settings for compatibility with ajaxSetup        settings = jQuery.extend(settings, jQuery.extend({}, jQuery.ajaxSettings, settings));        varport = settings.port;        switch(settings.mode) {            case"abort":                if(pendingRequests[port]) {                    pendingRequests[port].abort();                }                returnpendingRequests[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":                varpos = 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;                    }                };        }        returnajax.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”
就可以了。