zoukankan      html  css  js  c++  java
  • 解决一次要发出多个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);
        }
    });
    
    /*
    这种方法的唯一问题,就是在某些情况下--比如拖放式界面功能中--如果使用它,结果差不多会与传统页面重载的工作流一样令人讨厌。所以不能再脚本等待响应期间禁用拖动功能
     */
    
    // 增加资源占用
  • 相关阅读:
    Haskell Interactive Development in Emacs
    Access Java API in Groovy Script
    手工设置Eclipse文本编辑器的配色
    Color Theme of Emacs
    Gnucash的投资记录
    Special Forms and Syntax Sugars in Clojure
    Use w3m as Web Browser
    SSE指令集加速之 I420转BGR24
    【图像处理】 增加程序速度的方法
    TBB 入门笔记
  • 原文地址:https://www.cnblogs.com/Mr0909/p/4379447.html
Copyright © 2011-2022 走看看