ajax和它的超时

日常开发中一般都会使得ajax去获了数据,但有两点是需要值得注意的:

1、ajax请求队列

2、ajax的超时处理

为什么要注意这两点?为了让用户在其可视区域内更快速的看见内容。

假设页面结构分为三栏:左、中、右,而且页面数据会比较多,页面呈现的顺序则是是按从上而下执行的(当然是从左至右开始,一个模块一个模块加载数据),如果不采用队列,那么在页面可视范围之外的模块可能已经加载完数据了,而可视范围之内(假设为第一屏)的模块却尚未开始接收数据,这一类应用如:搜狐博客、新浪博客、网易博客等…

既然是采用了队列,那么又会有一个新的问题:需要保证一个请求的时候不能太长,不能因为一个请求而导致后续的请求被阻塞了。在这两点上jQuery做的其实都挺不错的。队列的处理上,已经有一个插件了,叫ajaxManager,例子和链接在这里:http://www.protofunc.com/scripts/jquery/ajaxManager/;而在超时的处理上,jquery本身就支持传递参数timeout来进行设置(默认是没有设置的)。它没有考虑IE8,尽管IE已经支持xhr对象的timeout属性。

从ajax创建开始,这里优化的一点是针对IE浏览器,只循环获取一次使用哪种MSXML库,副作用就是需要使用额外的属性来记录它

function createXHR() {
    if (typeof XMLHttpRequest != 'undefined') {
        return new XMLHttpRequest();
    } else if (typeof ActiveXObject != 'undefined')    {
        if (typeof arguments.callee.activeXString != 'string') {
            var version = ["MSXML2.XMLHTTP.6.0", "MSXML2.XMLHttp.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP"];

            for (var i = 0, len = version.length; i < len; ++i) {
                try {
                    var xhr = new ActiveXObject(versions[i]);
                    arguments.callee.activeXString = versions[i];
                    return xhr;
                }
                catch (ex){

                }
            }
        }

        return new ActiveXObject(arguments.callee.activeXString);
    } else {
        throw new Error("No XHR object available.");
    }
}

创建的xhr对象,它对应有5状态(readyState属性)

0   Uninitialized(尚未调用open方法)

1   Loading (已调用open,尚未调用send)

2   Loaded (已经调用send,尚未接收到响应)

3   Interactive (开始接收数据)

4   Complete (数据接收完毕,响应内容解析完成)

在判定一个请求是否已经完成的时候,验证xhr的status有一点是需要注意的:“有的浏览器会错误地返回204状态码”,而IE(非原生的XHR对象)中会将204设置为1223,Opera会在取得204时将status设置为0,而Safari 3之前的版本会将status设置为undefined

最终验证请求是否成功的代码将会是:

 ( xhr.status >= 200 && xhr.status < 300 ) ||
 xhr.status === 304 || xhr.status === 1223 || xhr.status === 0 

另外在send的时候,还需要注意的是如果不需要通过请求主体发送数据,最好是传入参数,因为send方法的参数

对于有些浏览器是必需的,建议一般传null即可

在发送请求时,可以通过setRequestHeader来设置HTTP头部信息,在使用GET请求时,可以在头部加上If-Modified-Since、Cache-Control参数来达到刷新缓存数据的目的(如果采用在URL上加随机数据或是时间戳,资源并没有被缓存)

 xhr.setRequestHeader('If-Modified-Since', 'Thu, 1 Jan 1970 00:00:00 GMT');
xhr.setRequestHeader('Cache-Control', 'no-cache'); 

在响应完成后,可以使用getResponseHeader、getAllResponseHeaders两个方法来获取指定或是全部的响应头的HTTP信息

剩下的一个问题是,处理ajax超时的问题。jquery中的做法是使用定时器来检测xhr的状态,而使用延时器来解决超时的问题:

setInterval(onreadystatechange, 13);

setTimeout(fn, timeout);

而在自定义的onreadystatechange函数中会检测传入的参数,如果参数为“timeout”则说明超时了,先调用xhr的abort取消请求,然后再调用complete方法。至于间隔时间为什么是13,这个没仔细去研究它

正常情况下,如果readyState为4,则先清除定时器,然后再检测响应的数据。而setTimeout中的fn函数,在处理时会先检测请求是否已经处理过了,这里它并没有对延时器进行引用,会导致的一种情况是,请求已经结束,延时器还在跑,直到达到指定的时间间隔。

最后如果ajax请求为异步的话,别忘记将xhr置为null==>xhr = null; 以防止内存泄漏的问题

IE8中直接写xhr.timeout = xxx;然后当超时时,会调用xhr的ontimeout方法,不过需要注意的问题是,当调用ontimeout事件时,此时的readyState可能已经变为了4,此时如果去访问status则会导致错误(最好使用try{}catch{}进行捕获一下)

到目前为止,除IE外,其它浏览器支持xhr对象的onload事件,只要浏览器开始接收到响应,就会触发它,所以在这个函数里面还是需要对它的status属性进行判断。

最后一点是在FF 1.5之后,它支持progress事件,这意味着可以显示当前请求的进度(不再是枯燥的loading了)。

在onprogress事件中会传入一个event对象,它的target是对应的xhr对象,它包含了两个额外的属性:position、totalSize。

其中position表示已接收的字节数,totalSize表示根据Content-Length响应头部确定的预期字节数。

 var xhr = new createXHR();
xhr.onload = function() {
    //...
}
xhr.onprogress = function(evt) {
    var percent = (evt.position / evt.totalSize)*100;
}
xhr.open("get", url, true);
xhr.send(null); 

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏豆包的专栏

共享内存无锁队列的实现

共享内存无锁队列是老调重弹了,相关的实现网上都能找到很多。但看了公司内外的很多实现,都有不少的问题,于是自己做了重新实现。主要是考虑了一些异常情况加强健壮性,并...

3.8K20
来自专栏技术换美食换不换

第二周实战作业:爬取一万商品数据

由于没有开time.sleep所以会被反扒, 卡死之后一般用ctrl+c停止那个类目爬取……

9220
来自专栏林冠宏的技术文章

全面总结: Golang 调用 C/C++,例子式教程

作者:林冠宏 / 指尖下的幽灵 掘金:https://juejin.im/user/587f0dfe128fe100570ce2d8 博客:htt...

1.1K50
来自专栏WeaponZhi

Python爬虫实践——简单爬取我的博客

学任何一门技术,如果没有实践,技术就难以真正的吸收。利用上次博客讲解的三个知识点:URL 管理器、网页下载器和网页解析器来爬取一下我的博客。 我的博客地址 ht...

38670
来自专栏Web行业观察

并发模型与事件循环 /mdn

JavaScript 的并发模型基于“事件循环”。这个模型与像 C 或者 Java 这种其它语言中的模型截然不同。

13740
来自专栏QQ会员技术团队的专栏

从 0 实现一个延迟代理服务

部门会定期进行容灾演习,也期望能够验证到各个服务的\"最差服务能力\"。即验证被调出现较高延迟或者过载的时候,主调的服务能力是否符合预期。要想做这种演习,其核心...

24220
来自专栏牛肉圆粉不加葱

Spark 内存管理的前世今生(上)

作为打着 “内存计算” 旗号出道的 Spark,内存管理是其非常重要的模块。作为使用者,搞清楚 Spark 是如何管理内存的,对我们编码、调试及优化过程会有很大...

15420
来自专栏生信宝典

Python文学化编程 - Jupyter notebook使用和插件拓展

Jupyter notebook (Ipython notebook)是集代码、结果、文档三位一体的文学化可重复程序文档。支持40多种程序语言,Python为原...

532100
来自专栏北京马哥教育

Linux命令行的艺术

熟练使用命令行是一种常常被忽视或被认为难以掌握的技能,但实际上,它可以提高你作为工程师的灵活性以及生产力。本文是一份我在 Linux 上工作时发现的一些关于命令...

55070
来自专栏Python攻城狮

Python数据科学(四)- 数据收集系列1.数据型态2.结构化vs半结构化vs非结构化数据3.Python IO与档案处理

◆ 定性分析: 分析: _ 知几写了很多篇文章 ◆ 定量分析: 分析:_ 知几写了107篇文章。

15120

扫码关注云+社区

领取腾讯云代金券