第三十二课:JSDeferred的性能提速

大家如果看了前面两课,就知道Deferred的静态方法next(next_default)是用setTimeout实现的(有浏览器最小时钟间隔)。但是实现这种异步操作,可以有很多种方法。JSDeferred中,针对老版本IE,以及标准浏览器都专门使用了一些方法来实现异步操作,提高异步操作的性能提速。

首先,我们先来看下针对老版本IE的提速。

Deferred.next_faster_way_readystatechange =

  (location.protocol == "http:") && IE &&    //这里的location是window对象下(document.location这样使用也行,)的一个属性对象,它有很多属性,比如:href,protocol等,href属性值是当前页面的URL地址(等于document.URL),protocol属性值是当前页面URL的协议,一般是"htttp:","https:"等。如果是http请求,并且是老版本IE浏览器,就继续

    function(fun){      //大家都知道&&的操作吧,前面如果都返回真,那么就返回后面这个。这里前面两个操作如果都返回真,那么这个&&操作会返回function。

      var d = new Deferred();

      var t = new Date().getTime();

      if( t - arguments.callee._prev_timeout_called < 150){    //这里先判断当前的时间与函数的_prev_timeout_called 属性值相减小于150毫秒就进入if语句。第一次执行时,函数的_prev_timeout_called 属性值是undefined,因此不会进入if语句(而使用原始的setTimeout方法)。第二次调用这个方法时,它会检查第二次调用这个方法与上一次调用这个方法的时间间隔,如果事件间隔小于150毫秒,就用速度更快的方法实现异步操作。如果超过了150毫秒,就用setTimeout方法实现。

        var cancel = false;

        var script = document.createElement("script");

        script.type = "text/javascript";

        script.src = "data:text/javascript";

        script.onreadystatechange = function(){   //加载一个不存在的资源,引发onerror,但是老版本IE不管是引发onerror还是onload都会引起onreadystatechange触发,因此就会执行这个函数。这里的异步操作时间非常短(在老版本IE下,这里的时间会短于setTimeout(function(){},0)的时间),但是足够让用户通过next实例方法绑定回调函数了。

          if(!cancel){

            d.canceller();

            d.call();

          }

        };

        d.canceller = function(){

          if(!cancel){

            cancel = true;

            script.onreadystatechange = null;

            document.body.removeChild(script);

          }

        };

        document.body.appendChild(script);    //因为这里需要把新建的script标签添加到页面中,所以我们的Deferred最好延迟到domReady或onload后执行

      }

      else{

        arguments.callee._prev_timeout_called = t;   //这里保存第一次执行此方法的时间,arguments.callee代表这个函数function(fun)。

        var id = setTimeout(function(){

          d.call();

        }, 0 );

        d.canceller = function(){

          clearTimeout(id);

        }

      }

      if(fun){

        d.callback.ok = fun;

      }

      return d    

    };

这里我要说下,为什么要设置一个150毫秒的时间。大家都知道当我们在老版本IE下进行jsonp操作时,浏览器会进行请求,每新建一个script,并且设置它的src,并添加到页面上就会进行请求。如果不设置这个150毫秒的时间,那么如果每次异步操作都使用这种jsonp的方式,那么浏览器会同时进行N多个请求。而大家知道,IE6-7下,浏览器的并发请求是2-4个,IE8-9是6个。如果多余这个数量,那么请求就会被堵塞。导致使用这种方式的异步操作,时间花的更长,那这提速方法,就没有意义了。因此,我们在这里设置一个150毫秒的时间,在150毫秒内,它的jsonp的请求不可能会出现很多个。我们来举个例子:第一次异步操作,默认会使用setTimeout的方法,这时的时间是0(保存为_prev_timeout_called ),第二次异步操作,时间是40毫秒,小于150,所以使用jsonp方式,第三次异步操作,时间是80毫秒,小于150,使用jsonp方式,第四次异步操作,时间是120毫秒,小于150,使用jsonp方式。当第五次异步操作来临时,它的当前时间是160毫秒,这时160-_prev_timeout_called =160>150,使用setTimeout方式,并且保存_prev_timeout_called为160。因此,这里同时使用了三次jsonp方式,浏览器的并发请求是3个,没有超过浏览器的并发请求数,不会堵塞。

针对标准浏览器的加速如下:

Deferred.next_faster_way_image = !window.opera && document.addEventListener &&   //标准浏览器,并且不是opera浏览器,就继续。

  function(fun){

    var d = new Deferred();

    var img = new Image();

    var handler = function(){

      d.canceller();

      d.call();

    };

    img.addEventListener("load",handler,false);      //加载一个不存在的图片,会触发error事件。之所有绑定了onload事件,以防图片存在。

    img.addEventListener("error",handler,false);      

    d.canceller = function(){

      img.removeEventListener("load",handler,false);

      img.removeEventListener("error",handler,false);

    };

    img.src = "data:image/png," + Math.random();   //这里之所以加上随机数,是因为图片会缓存,以防图片存在的情况下被缓存了,这样就不会发请求,也就不会有异步效果了。

    if(fun){

      d.callback.ok = fun;

    }

    return d;

  };

根据JSDeferred官方的数据,用上这两个后,比原来的setTimeout异步方式快了700%以上。

JSDeferred不单单是运行于网页上,它还能在浏览器的插件环境以及node.js上运行。node.js已经支持快的惊人的最新异步API:setImmediate方法了。

当然,这些提速的方式因为都属于异步操作,因此都会有延迟效果,最快的方式就是不使用异步操作,jQuery Deferred就是使用精妙数组结构实现的,下一课将详细讲解它。

加油!

时间: 2024-07-29 00:43:34

第三十二课:JSDeferred的性能提速的相关文章

第三十二课 二维数组及其定义 【项目1-2】

第三十二课  二维数组及其定义 项目一 [折腾二维数组] 创建一个5行4列的二维整型数组,通过初始化,为数组中的前两列的10个元素赋初值,然后: 通过键盘输入,使后两列的10个元素获得值: 按行序优先输出数组元素: 将所有元素值乘以3后保存在数组中: 按列序优先输出(输出的第一行是数组中的第一列--,其实输出的就是"转置"): 将数组"倒"着输出(即最后一行最后一列的最先输出,第0行第0列的最后输出): 输出数组中的所有偶数: 输出所有行列下标之和为3的倍数的元素值

2018-07-30 第三十二课

第三十二次课 shell编程(二) 目录 十五.shell中的函数 十六.shell中的数组 十七.告警系统需求分析 十八.告警系统主脚本 十九.告警系统配置文件 二十.告警系统监控项目 二十一.告警系统邮件引擎 二十二.运行告警系统 十五.shell中的函数 函数就是把一段代码整理到了一个小单元中,并给这个小单元起一个名字,当用到这段代码时直接调用这个小单元的名字即可.定义函数必须要放在最前面.定义好的函数相当于是命令. 语法格式 //name属性定义了赋予函数的唯一名称.脚本中定义的每个函数

第三十二课、Qt中的文件操作

一.Qt中的IO操作 1.Qt中IO操作的处理方式 (1).Qt通过统一的接口简化了文件与外部设备的操作方式 (2).Qt中的文件被看做是一种特殊的外部设备 (3).Qt中的文件操作与外部设备操作相同 2.IO操作中的关键函数接口 注意:IO操作的本质:连续存储空间的数据读写 3.Qt中IO设备类型 (1).顺序存储设备:只能从头开始顺序读写数据,不能指定数据的读写位置(串口) (2).随机存储设备:可以定位到任意位置进行数据读写(seek function函数)(文件) 4.Qt中IO设备 的

AGG第三十二课 renderer_outline_aa更快的渲染线段算法

留给:曾经在校园奔跑时候,摔破膝盖,擦伤手掌的孩子! 1 前言 本章提供了采用新的线段渲染算法的例子,相比于已经实现的stroke管道算法,平均提高了2倍的速度,最好的情况下是2.6倍加速度.当然这种算法应用在细线上速度才会快,最好是小于2个像素. 在其他的章节中会跟conv_stroke进行效率的对比.同样的避免不了引入更多的限制,这一点可以在下面了解到.多说一句:conv_stroke是最昂贵的转换器. The rasterizer itself works much faster, bes

JAVA学习第三十二课(常用对象API)- 基本数据类型对象包装类

将基本数据类型(8种:int..)封装成对象的好处就是可以在对象中封装更多的功能和方法来操控该数据 常见的操作就是:用于基本数据类型与字符串之间的转换 基本数据类型对象包装类一般用于基本类型和字符串之间的转换 基本类型----->字符串 1.基本类型数值+"" 2.用string类中的valueOf(基本类型数值) 3.用Integer.ValueOf(); 字符串-->基本类型数值 1.使用包装类中的静态方法XXX  parseXXX("XXXX")比

第三十二课 linux内核链表剖析

__builtin_prefetch是gcc扩展的,用来提高访问效率,需要硬件的支持. 在标准C语言中是不允许static inline联合使用的. 删除依赖的头文件,将相应的结构拷贝到LinuxList.h中: 此外,需要将container_of改写成我们自己的形式. 1 #define container_of(ptr, type, member) ((type *)((char *)ptr - offsetof(type,member))) 移植后的内核链表如下: 1 #ifndef _

python第三十二课——栈

栈:满足特点 --> 先进后出,类似于我们生活中的子弹夹 [注意] 对于栈结构而言:python中没有为其封装特定的函数,我们可以使用list(列表)来模拟栈的特点 使用list对象来模拟栈结构存取数据的特点:先进后出 # 定义一个列表对象,stack(变量名.引用名) stack=[] # 向栈中添加数据(模拟压栈) stack.append('A') print(stack) stack.append('B') print(stack) stack.append('C') print(sta

第三十四课 二维数组的存储 【项目1-3】

第三十四课 二维数组的存储 项目一[二维数组当函数参数] 定义一个函数来完成对参数数组中元素的求和工作,函数声明如下: [cpp] view plain copy print? int sum(int array[ ][4],int m,int n);  //该函数完成对array数组中的前m行和n列元素求和 在以下程序的基础上,完成对sum函数的定义. [cpp] view plain copy print? #include <stdio.h> int sum(int array[ ][4

NeHe OpenGL教程 第四十二课:多重视口

转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢. NeHe OpenGL第四十二课:多重视口 多重视口 画中画效果,很酷吧.使用视口它变得很简单,但渲染四次可会大大降低你的显示速度哦:) 欢迎来到充满趣味的另一课.这次我将向你展示怎样在单个窗口内显示多个视口.这些视口在窗口模式下能正确的调整大小.其中有