Skip to main content
 首页 » 编程设计

jQuery Ajax 请求队列详解

2022年07月16日23qq78292959
/* 
 完成请求的赛跑 
 
 异步请求几乎同时发生,但却不会同步而且次序经常颠倒。 
 
 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); 
    } 
}); 
 
/* 
这种方法的唯一问题,就是在某些情况下--比如拖放式界面功能中--如果使用它,结果差不多会与传统页面重载的工作流一样令人讨厌。所以不能再脚本等待响应期间禁用拖动功能 
 */ 
 
// 增加资源占用

本文参考链接:https://www.cnblogs.com/webFrontDev/archive/2013/02/01/2888584.html