zoukankan      html  css  js  c++  java
  • JavaScript之定时器性能优化

    JavaScript之定时器性能优化

          在JavaScript中使用setTimeout()或setInterval()创建定时器,两个函数都接收一样的参数:一个要执行的函数,和一个运行它之前的等待时间(单位毫秒)。setTimeout()函数创建一个定时器只运行一次,而setInterval()函数创建一个周期性重复运行的定时器。
          定时器与UI线程交互的方式有助于分解长运行脚本成为较短的片断。调用setTimeout()或setInterval()告诉JavaScript引擎等待一定时间然后将JavaScript任务添加到UI队列中。例如:
          function greeting(){
                alert("Hello world!");
          }
          setTimeout(greeting, 250);
          此代码将在250毫秒之后,向UI队列插入一个JavaScript任务运行greeting()函数。在那个点之前,所有其他UI更新和JavaScript任务都在运行。请记住,第二个参数指出什么时候应当将任务添加到UI队列之中,并不是说那时代码将被执行。这个任务必须等到队列中的其他任务都执行之后才能被执行。考虑下面的例子:

          var button = document.getElementById("my-button");
          button.onclick= function(){
                oneMethod();
                setTimeout(function(){
                      document.getElementById("notice").style.color = "red";
                }, 250);
          };
          在这个例子中当按钮被点击时,它调用一个方法然后设置一个定时器。用于修改notice元素颜色的代码被包含在一个定时器设备中,将在250 毫秒之后添加到队列。250 毫秒从调用setTimeout()时开始计算,而不是从整个函数运行结束时开始计算。如果setTimeout()在时间点n 上被调用,那么运行定时器代码的JavaScript任务将在n+250的时刻加入UI队列。
          请记住,定时器代码只有等创建它的函数运行完成之后,才有可能被执行。例如,如果前面的代码中定时器延时变得更小,然后在创建定时器之后又调用了另一个函数,定时器代码有可能在onclick事件处理完成之前加入队列:
          var button = document.getElementById("my-button");
          button.onclick= function(){
                oneMethod();
                setTimeout(function(){
                      document.getElementById("notice").style.color = "red";
                }, 50);
                anotherMethod();
          };
          如果anotherMethod()执行时间超过50毫秒,那么定时器代码将在onclick处理完成之前加入到队列中。其结果是等onclick处理运行完毕,定时器代码立即执行,而察觉不出其间的延迟。
          在任何一种情况下,创建一个定时器造成UI线程暂停,如同它从一个任务切换到下一个任务。因此,定时器代码复位所有相关的浏览器限制,包括长运行脚本时间。此外,调用栈也在定时器代码中复位为零。这一特性使得定时器成为长运行JavaScript代码理想的跨浏览器解决方案。
          如果调用setTimeout()的函数又调用了其他任务,耗时超过定时器延时,定时器代码将立即被执行,它与主调函数之间没有可察觉的延迟。
          一、定时器精度
          JavaScript定时器延时往往不准确,快慢大约几毫秒。仅仅因为你指定定时器延时250 毫秒,并不意味任务将在调用setTimeout()之后精确的250 毫秒后加入队列。所有浏览器试图尽可能准确,但通常会发生几毫秒滑移,或快或慢。正因为这个原因,定时器不可用于测量实际时间。
          在Windows 系统上定时器分辨率为15毫秒,也就是说一个值为15的定时器延时将根据最后一次系统时间刷新而转换为0 或者15。设置定时器延时小于15将在Internet Explorer中导致浏览器锁定,所以最小值建议为25毫秒(实际时间是15或30)以确保至少15毫秒延迟。
          此最小定时器延时也有助于避免其他浏览器和其他操作系统上的定时器分辨率问题。大多数浏览器在定时器延时小于10毫秒时表现出差异性。
          二、在数组处理中使用定时器
          一个常见的长运行脚本就是循环占用了太长的运行时间。如果你已经尝试了循环优化技术,但还是不能缩减足够的运行时间,那么定时器就是你的下一个优化步骤。其基本方法是将循环工作分解到定时器序列中。
          典型的循环模式如下:
          for (var i=0, len=items.length; i < len; i++){
                process(items[i]);
          }
          这样的循环结构运行时间过长的原因有二,process()的复杂度,items的大小,或两者兼有。是否可用定时器取代循环的两个决定性因素:
          (1)此处理过程必须是同步处理吗?
          (2)数据必须按顺序处理吗?
          如果这两个回答都是“否”,那么代码将适于使用定时器分解工作。一种基本异步代码模式如下:
          var todo = items.concat();
          setTimeout(function(){
                process(todo.shift());
                if(todo.length > 0){
                      setTimeout(arguments.callee, 25);
                } else {
                      callback(items);
                }
          }, 25);
          这一模式的基本思想是创建一个原始数组的克隆,将它作为处理对象。第一次调用setTimeout()创建一个定时器处理队列中的第一个项。调用todo.shift()返回它的第一个项然后将它从数组中删除。此值作为参数传给process()。然后,检查是否还有更多项需要处理。如果todo 队列中还有内容,那么就再启动一个定时器。因为下个定时器需要运行相同的代码,所以第一个参数传入arguments.callee。此值指向当前正在运行的匿名函数。如果不再有内容需要处理,将调用callback()函数。
          此模式与循环相比需要更多代码,可将此功能封装起来。例如:
          function processArray(items, process, callback){
                var todo = items.concat();
                setTimeout(function(){
                      process(todo.shift());
                      if (todo.length > 0){
                            setTimeout(arguments.callee, 25);
                      } else {
                            callback(items);
                      }
                }, 25);
          }
          processArray()函数以一种可重用的方式实现了先前的模板,并接收三个参数:待处理数组,对每个项调用的处理函数,处理结束时执行的回调函数。该函数用法如下:
          var items = [123, 789, 323, 778, 232, 654, 219, 543, 321, 160];
          function outputValue(value){
                console.log(value);
          }
          processArray(items, outputValue, function(){
                console.log("Done!");
          });
          此代码使用processArray()方法将数组值输出到终端,当所有处理结束时再打印一条消息。通过将定时器代码封装在一个函数里,它可在多处重用而无需多次实现。

  • 相关阅读:
    用python实现average()函数,使得当可变参数长度为0的时候,也能正确返回结果。
    请用python实现函数func,当参数类型为list时,返回list中所有数字类型元素的和,当参数类型为tuple时,返回tuple中所有数字类型元素的乘积。
    用python实现循环和递归的形式定义函数,求出1~100的和。
    python实现0~100的平方和,用sum()函数接收一个list作为参数,并返回list所有元素之和。请计算 1*1 + 2*2 + 3*3 + ... + 100*100。
    用python实现线性回归
    IE11用JS检测判断
    Google Chrome的CSS hack写法
    javascript间窗口互相通信,window.open新建窗口保存父窗口对象
    解决IE6不支持css min-width与min-height
    CSS实现兼容性的渐变背景(gradient)效果(转)
  • 原文地址:https://www.cnblogs.com/taocom/p/3054147.html
Copyright © 2011-2022 走看看