解決一次要發出多個ajax請求


jquery ajax隊列管理插件

不錯的ajax的jquery隊列管理器

;(function($) {
 function AjaxQueue(override) {
 this.override = !!override;
 };
 AjaxQueue.prototype = {
 requests: new Array(),
 offer: function(options) {
 var _self = this;
 var xhrOptions = $.extend({}, options, {
 complete: function(jqXHR, textStatus) {
 if($.isArray(options.complete)) {
 var funcs = options.complete;
 for(var i = 0, len = funcs.length; i < len; i++)
 funcs[i].call(this, jqXHR, textStatus);
 } else {
 if(options.complete)
 options.complete.call(this, jqXHR, textStatus);
 }
 _self.poll();
 },
 beforeSend: function(jqXHR, settings) {
 if(options.beforeSend)
 var ret = options.beforeSend.call(this, jqXHR, settings);
 if(ret === false) {
 _self.poll();
 return ret;
 }
 }
 });
 if(this.override) {
 this.replace(xhrOptions);
 } else {
 this.requests.push(xhrOptions);
 if(this.requests.length == 1) {
 $.ajax(xhrOptions);
 }
 }
 },
 replace: function(xhrOptions) {
 var prevRet = this.peek();
 if(prevRet != null) {
 prevRet.abort();
 }
 this.requests.shift();
 this.requests.push($.ajax(xhrOptions));
 },
 poll: function() {
 if(this.isEmpty()) {
 return null;
 }
 var processedRequest = this.requests.shift();
 var nextRequest = this.peek();
 if(nextRequest != null) {
 $.ajax(nextRequest);
 }
 return processedRequest;
 },
 peek: function() {
 if(this.isEmpty()) {
 return null;
 }
 var nextRequest = this.requests[0];
 return nextRequest;
 },
 isEmpty: function() {
 return this.requests.length == 0;
 }
 };
 var queue = {};
 var AjaxManager = {
 createQueue: function(name, override) {
 return queue[name] = new AjaxQueue(override);
 },
 destroyQueue: function(name) {
 if(queue[name]) {
 queue[name] = null;
 delete queue[name];
 }
 },
 getQueue: function(name) {
 return ( queue[name] ? queue[name] : null);
 }
 };
 $.AM = AjaxManager;
})(jQuery);
使用示例:
var newQueue = $.AM.createQueue('queue');
$(function(){
          newQueue.offer({url:'?c=Message&m=write&a=10'});
          newQueue.offer({url:'?c=Message&m=write&a=10'});
          newQueue.offer({url:'?c=Message&m=write&a=1'});
});

第二個插件

(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);



(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高級程序設計上的。

/*
 * 將ajax根據優先級進行排列的方法
 * 構造一個簡單的排列函數,接受一個排序的函數
 * 所有添加的ajax保存到_items中
 * 
 */
function PriorityQueue(fn){
    this._items = [];
    if(typeof fn == 'function'){
        this._compare = fn;
    }
}
 
PriorityQueue.prototype = {
    constructor:PriorityQueue,
    _compare:function(oValue1,oVlaue2){
        if(oValue1<oVlaue2){
            return -1;
        }else if(oValue1 > oVlaue2){
            return 1;
        }else{
            return 0;
        }
    },
    //排序
    prioritze:function(){
        this._items.sort(this._compare)
    },
    //移除並返回第一個ajax  
    get:function(){
        return this._items.shift();
    },
    //返回對列中指定的ajax
    item:function(iPos){
        return this._items[iPos];
    },
    //返回隊列中第一個ajax
    peek:function(){
        return this._items[0];
    },
    //將一個ajax插入到隊列中,並排序
    put:function(oValue){
         this._items.push(oValue);
         this.prioritze();
    },
    //返回隊列的長度
    size:function(){
        return this._items.length;
    },
    //移除一個指定的ajax,成功后返回true,否則false
    remove:function(oValue){
        for(var i=0,len=this._items.length;i<len;i++){
            if(this._items[i] == oValue){
                this._items.splice(i,1);  
                return true;
            }
        };
        return false;
    }
}
 
/*
 * 
 * 
 */
var RequestManager = (function(){
    var oManager =  {
        //隊列是最長等待時間
        AGE_LIMIT:60000,
        //默認優先級10
        DEFAULT_PRIORTY:10,
        //檢查隊列時間間隔
        INTERVAL:250,
        //保存正在執行的ajax
        _active:[],
        //隊列實例
        _pending:new PriorityQueue(function(oRequest1,oRequest2){
            return oRequest1.priority - oRequest2.priority;
        }),
        //檢查每個ajax的等待時間,如果超出默認的最長時間,則提高該ajax的優先級
        _agePromote:function(){
            for(var i=0;i<this._pending.size();i++){
                var oRequest = this._pending._items[i];
                oRequest.age += this.INTERVAL;
                if(oRequest.age >= this.AGE_LIMIT){
                    oRequest.age = 0;
                    oRequest.priority--;
                };
            };
            this._pending.prioritze();
        },
        //檢查正在執行的ajax狀態,
        _checkActiveRequests:function(){
            var oRequest = null;
            var oTransport = null;
             
            for(var i=this._active.length-1; i>=0; i--){
                oRequest = this._active[i];
                oTransport = oRequest.transport;
                if(oTransport.readyState == 4){
                    oRequest.active = false;
                    this._active.splice(i,1);
                    var fnCallback = null;
                    if(oTransport.status >= 200 && oTransport.status < 300){
                        if(typeof oRequest.onsuccess == 'function'){
                            fnCallback = oRequest.onsuccess;
                        }
                    }else if(oTransport.status == 304){
                        if(typeof oRequest.onnotmodified == 'function'){
                            fnCallback = oRequest.onnotmodified;
                        }
                    }else{
                        if(typeof oRequest.onfailure == 'function'){
                            fnCallback = oRequest.onfailure;
                        }
                    }
                    if(fnCallback != null){
                        setTimeout((function(fnCallback,oRequest,oTransport){
                            return function(){
                                 fnCallback.call(oRequest.scope||window, { 
                                    status : oTransport.status, 
                                    data : oTransport.responseText, 
                                    request : oRequest
                                })
                            }
                        })(fnCallback,oRequest,oTransport),1);
                    }
                }
            }
        },
        //封裝XMLHttpRequest
        _createTransprot:function(){
            if(typeof XMLHttpRequest != 'undefined'){
                return new XMLHttpRequest();
            }else if(typeof ActiveXObject != 'undefined'){
                var xhr = null;
                try{
                    xhr = new ActiveXObject('MSXML2.XmlHttp.6.0');
                    return xhr;
                }catch(e){
                    try{
                        xhr  = new ActiveXObject('MSXML2.XmlHttp.3.0');
                        return xhr;
                    }catch(e){
                        throw Error('cannot create XMLHttp object!');
                    }
                }
            }
        },
        //發送一下個請求,檢查當前執行的ajax是否小於2,如果是,則激活下一個ajax
        _sendNext:function(){
            if(this._active.length <2){
                var oRequest = this._pending.get();
                if(oRequest != null){
                    this._active.push(oRequest);
                    oRequest.transport = this._createTransprot();
                    oRequest.transport.open(oRequest.type,oRequest.url,true);
                    oRequest.transport.send(oRequest.data);
                    oRequest.active = true;
                }
            }
        },
        //取消指定的ajax,如果有回調函數oncancel,則執行
        cancel:function(oRequest){
            if(!this._pending.remove(oRequest)){
                oRequest.transport.abort();
                if(this._active[0] === oRequest){
                    this._active.shift();
                }else if(this._active[1] === oRequest){
                    this._active.pop();
                };
                if(typeof oRequest.oncancel == 'function'){
                    oRequest.oncancel.call(oRequest.scope||window,{request:oRequest})
                }
            }
        },
        //添加一個ajax到隊列中
        send:function(oRequest){
            if(typeof oRequest.priority != 'number'){
                oRequest.priority = this.DEFAULT_PRIORTY;
            };
            oRequest.active = false;
            oRequest.age = 0;
            this._pending.put(oRequest);
        },
         
        /*
         * 預置一些方面,方便不知道該如何設置優先的情況
         * 其實也就是給這些方法加了個默認的優先級
         */
        poll:function(oRequest){
            oRequest.priority = 3;
            this.send(oRequest);
        },
         
        prefetch:function(oRequest){
            oRequest.priority = 5;
            this.send(oRequest);
        },
         
        submit:function(oRequest){
            oRequest.priority = 0;
            this.send(oRequest);
        },
         
        submitPart:function(oRequest){
            oRequest.priority = 2;
            this.send(oRequest);
        },
    };
    //通過setInterval,不斷的檢查隊列中ajax執行情況,
    //如果執行完,添加下一個
    //如果超過最長等待時間,則提高優先級
    //據說這里之所以不用onreadystatechange是為了避免IE下的內存問題
    //但感覺這樣在頁面上不停的setinterval,同樣讓人蛋疼啊!
    setInterval(function(){
        RequestManager._checkActiveRequests();
        RequestManager._sendNext();
        RequestManager._agePromote();
    },oManager.INTERVAL);
     
    return oManager;
})();
 
/*
用法:
    RequestManager.send({
        priority:0,
        type:'get',
        url:'data.txt',
        onsuccess:function(){},
        onfailure:function(){},
        onnotmodified:function(){}
    })
*/

 第四:

/*
 完成請求的賽跑

 異步請求幾乎同時發生,但卻不會同步而且次序經常顛倒。

 1.延遲決定勝利者
 在賽跑過程中,無論是服務器還是腳本都無法使某個請求更快地得到響應。請求過程中的延遲會出現在幾個階段,而其中的多個階段都是你無法控制的。
 所有通信過程都將遵循如下相同的模式:
 (1)客戶端計算機對服務器發起獲取或修改信息的請求。
 (2)將請求通過一條計算機網絡發送到服務器。
 (3)服務器處理請求。
 (4)服務器將對請求的響應通過另一條計算機網絡發送回客戶端計算機
 在這個請求/相應循環的過程中,每個階段都存在外部因素的影響。

 2.處理異步請求
 處理請求/響應循環中的延遲問題有很多不同的方式。以下是其中幾種主要的思路:
 (1)置之不理。
 (2)關掉異步行為。 在Ajax對象中設置asynchronous=false是另外一種選擇,但這個選擇也可以從你的方案清單中划掉。如果在XMLHttpRequest對象上設置了同步模式,那么它會按照次序處理請求,但它是通過把請求轉換為一種更加激進的阻塞模式來實現這一點的。在這種情況下,你的腳本將被迫停止運行直至請求完成,期間可能會因為響應過慢而導致腳本和瀏覽器被掛起。

 3.在客戶端隊請求排隊
 排隊是另一種可能的方案。與其一次發送多個XMLHttpRequest請求,不如等到前一個請求獲得相應后再發送下一個。

 */

/* 一個復制對象的輔助方法 */
function clone(myObj) {
    if (typeof myObj !== 'object') {
        return myObj;
    }
    if (myObj === null) {
        return myObj;
    }
    var myNewObj = {};
    for (var i in myObj) {
        myNewObj[i] = clone(myObj[i]);
    }
    return myNewObj;
}

/* 用於保存隊列的數組 */
var requestQueue = [];

/**
 * 為ADS.ajaxRequest方法啟用排隊功能的包裝對象
 * @param url
 * @param options
 * @param queue
 * @example
 *      ADS.ajaxRequestQueue('/your/script/', {
     *          completeListener: function(){
     *              alert(this.responseText);
     *          }
     *      }, 'Queue1');
 */
function ajaxRequestQueue(url, options, queue) {
    queue = queue || 'default';

    // 這個對象將把可選的偵聽器包裝在另一個函數中
    // 因此,可選的對象必須唯一。否則,如果該方法
    // 被調用時使用的是共享的可選對象,那么會導致
    // 陷入遞歸中
    options = clone(options) || {};
    if (!requestQueue[queue]) {
        requestQueue[queue] = [];
    }

    // 當前一次請求完成時,需要使用completeListener
    // 調用隊列中的下一次請求。如果完成偵聽器已經
    // 有定義,那么需要首先調用它

    // 取得舊偵聽器
    var userCompleteListener = options.completeListener;

    // 添加新偵聽器
    options.completeListener = function () {
        // 如果存在舊的偵聽器則首先調用它
        if (userCompleteListener) {
            // this引用的是情求對象
            userCompleteListener.apply(this, arguments);
        }

        // 從隊列中移除這個請求
        requestQueue[queue].shift();

        // 調用隊列中的下一項
        if (requestQueue[queue][0]) {
            // 請求保存在req屬性中,但為防止它是
            // 一個POST請求,故也需包含send選項
            var q = requestQueue[queue][0].req.send(
                    requestQueue[queue][0].send
            );
        }
    };

    // 如果發生了錯誤,應該通過調用相應的
    // 錯誤處理方法取消隊列中的其他請求

    // 取得舊偵聽器
    var userErrorListener = options.errorListener;

    // 添加新偵聽器
    options.errorListener = function () {
        if (userErrorListener) {
            userErrorListener.apply(this, arguments);
        }

        // 由於已經調用了錯誤偵聽器
        // 股從隊列中移除這個請求
        requestQueue[queue].shift();

        // 由於出錯需要取消隊列中的其余請求,但首先要調用
        // 每個請求的errorListener。通過調用隊列中
        // 下一項的錯誤偵聽器就會才清楚所有排隊的請求,因為在
        // 鏈中的調研那個是一次發生的

        // 檢測隊列中是否還存在請求
        if (requestQueue[queue].length) {
            // 取得下一項
            var q = requestQueue[queue].shift();

            // 中斷請求
            q.req.abort();

            // 偽造請求對象,以便errorListener
            // 認為請求已經完成並相應地運行

            var fakeRequest = {};

            // 將status設置為0,將readyState設置為4
            // 就好像請求雖然完成但卻失敗了一樣
            fakeRequest.status = 0;
            fakeRequest.readyState = 4;

            fakeRequest.responseText = null;
            fakeRequest.responseXML = null;

            // 設置錯誤信息,以便需要時顯示
            fakeRequest.statusText = 'A request in the queue received an error';

            // 調用狀態改變,如果readyState是4,而
            // status不是200,則會調用errorListener
            q.error.apply(fakeRequest);
        }
    };

    // 將這個請求添加到隊列中
    requestQueue[queue].push({
        req: getRequestObject(url, options),
        send: options.send,
        error: options.errorListener
    });

    // 如果隊列的長度表明只有一個
    // 項(即第一個)則調用請求
    if (requestQueue[queue].length === 1) {
        ajaxRequest(url, options);
    }
}

window.ADS.ajaxRequestQueue = ajaxRequestQueue;

//隊列中的請求1
ADS.ajaxRequestQueue('/your/script/', {
    completeListener: function () {
        alert(this.responseText);
    }
}, 'Queue1');
//隊列中的請求2
ADS.ajaxRequestQueue('/your/script/', {
    completeListener: function () {
        alert(this.responseText);
    }
}, 'Queue2');
//隊列1中的請求1,要等到請求1完成
ADS.ajaxRequestQueue('/your/script/', {
    completeListener: function () {
        alert(this.responseText);
    }
}, 'Queue1');
// 隊列1與隊列2會在同一時刻以異步方式運行

/*
 4.令請求異步但禁用有沖突的功能
 禁用功能可能是避免不協調問題的最常見方法了。當執行某些異步請求時,讓用戶知道后台在干什么永遠是很重要的。而這通常是通過在請求等待響應期間顯示“載入中”等信息或者動畫來完成。在等待期間,用戶可能會猶豫急不可耐而在載入完成之前有執行了相同的操作,那么就可能對程序造成潛在的破壞。
 除了顯示簡單的“載入中”信息之外,還可以禁用程序中的某個部件,以防止用戶在不耐煩的情況下重復操作。而實現這一點的唯一技巧,就是無論是響應成功,還是發生了錯誤都要重新啟用所禁用的部件。
 */

// 例如:Web應用程序中包含如下提交按鈕
// <input type="submit" id="buttonID">
// 那么,就可以禁用表單提交功能
ADS.ajaxRequest('/your/script/', {
    loadListener: function () {
        // 在載入期間禁用按鈕
        ADS.$('buttonID').disabled = 'disabled';
    },
    completeListener: function () {
        // 當響應成功時啟用按鈕
        ADS.$('buttonID').disabled = '';
        alert(this.responseText);
    },
    errorListener: function () {
        // 當發生錯誤時也要啟用按鈕
        ADS.$('buttonID').disabled = '';
        alert('Oops, please try again:' + this.statusText);
    }
});

/*
這種方法的唯一問題,就是在某些情況下--比如拖放式界面功能中--如果使用它,結果差不多會與傳統頁面重載的工作流一樣令人討厭。所以不能再腳本等待響應期間禁用拖動功能
 */

// 增加資源占用

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM