zoukankan      html  css  js  c++  java
  • Ajax详解3请求队列

    /*
     完成请求的赛跑
    
     异步请求几乎同时发生,但却不会同步而且次序经常颠倒。
    
     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);
        }
    });
    
    /*
    这种方法的唯一问题,就是在某些情况下--比如拖放式界面功能中--如果使用它,结果差不多会与传统页面重载的工作流一样令人讨厌。所以不能再脚本等待响应期间禁用拖动功能
     */
    
    // 增加资源占用
  • 相关阅读:
    vue强制更新$forceUpdate()
    js数组拼接成字符串,去除最后一个逗号
    JavaScript数组遍历:for、foreach、for in、for of、、().each的区别
    json.stringify()的妙用,json.stringify()与json.parse()的区别
    第四次博客作业-结对项目
    于达——第九次作业
    于达——第八次作业
    软件工程第三次作业——关于软件质量保障初探
    于达——第七次作业
    于达——第六次作业
  • 原文地址:https://www.cnblogs.com/webFrontDev/p/2888584.html
Copyright © 2011-2022 走看看