• 解决一次要发出多个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);
        }
    });
    
    /*
    这种方法的唯一问题,就是在某些情况下--比如拖放式界面功能中--如果使用它,结果差不多会与传统页面重载的工作流一样令人讨厌。所以不能再脚本等待响应期间禁用拖动功能
     */
    
    // 增加资源占用
  • 相关阅读:
    spring19
    springmvc19
    Android打开数据库读取数据
    家庭记账本开发第二天
    家庭记账本开发第一天
    体温填报小程序完结
    一个抽取百度定位的教程(下载百度地图Demo+配置+抽取)
    将百度地图Demo抽取出来安到自己的程序中
    Android定位
    体温数据上传程序开发+获取时间的三种方法+DB Browser下载及安装
  • 原文地址:https://www.cnblogs.com/Mr0909/p/4379447.html
Copyright © 2020-2023  润新知