Javascript定时器学习笔记

  掌握定时器工作原理必知:JavaScript引擎是单线程运行的,浏览器无论在什么时候都只且只有一个线程在运行JavaScript程序. 常言道:setTimeout和setInterval是伪线程。

  Javascript是运行在单线程环境中的,在页面的声明周期中,不同时间可能有其他代码在控制Javascript进程,比如:包含在<script>元素中的代码、dom元素的事件处理程序、Ajax的回调函数。定时器仅仅是在未来的某个时刻将代码添加到代码队列中,执行时机是不能保证的。代码队列按照先进先出的原则在主进程空闲后将队列中的代码交给主线程运行。

  

  在不同时间段内Javascript主进程处于不同状态,开始时执行页面中<script>元素内的代码,初始加载完成后,主进程进入空闲状态,这时候有dom元素产生click事件,事件处理代码被添加到代码队列中,代码队列发现Javascript主进程处于空闲状态,立即将队列中的第一个元素交给主进程执行。上图便是这一个过程的时间线。

  在Javascript中没有任何代码是立刻执行的,带一旦进程空闲则尽快执行。例如,当某个按钮被按下时,事件处理函数会被添加到代码队列中。当接收到ajax响应时,回校函数的代码被添加到队列中。而定时器对队列的工作方式是,当特定的事件过去后将代码加入到队列中。设定一个150ms后执行的定时器不代表代码会在150ms之后执行,而是指代码会在150ms后加入到代码队列中。等到主进程空闲时并且该元素位于队列首位,其中的代码便会立即执行,看上去好像是在精确的时间点上执行了。实际上队列中的所有代码都要等到主进程空闲之后才能执行,而不管他们是怎额添加到队列中去的。

var ele = document.getElementById(‘btn‘);
ele.onclick = function(){
    setTimeout(function(){
        document.getElementById(message).style.backgroundColor = "red";
    }, 255);
    var start = Date.now();
    while(Date.now() - start < 300) {};
}

  以上示例中,定时器在255ms事被插入到代码队列中,但Javascript主线程有300ms处于运行状态,那么定时器代码至少要在定时器设置之后的300ms后才会被执行。以下时间线代表了上面代码的执行过程。

  

  重复定时器setInterval

  为了确保定时器代码插入到队列总的最小间隔为指定时间。当使用setInterval()时,仅当没有该定时器的任何其他代码实例时,才能将定时器代码添加到代码队列中。假设没有这条原则,setInterval()创建的定时器确保了定时器代码能够规则的插入队列中。那么问题来了,假设Javascript主进程的运行时间非常长,那么setInterval的代码被多次添加到了代码队列中,等到主进程空闲时,定时器代码便会连续执行多次而之间不会有任何停顿。

  但是这条规则同样也带来了两个问题:

  1. 某些间隔会被跳过
  2. 多个定时器的代码执行之间的间隔可能会比预期的小
var ele = document.getElementById(‘btn‘);
ele.onclick = function(){
    setInterval(function(){    console.log(‘run interval‘);
        var start = Date.now();
        while(Date.now() - start < 350) {};
    }, 200);
    var start = Date.now();
    while(Date.now() - start < 300) {};
}

  以上代码中,click事件处理程序中通过setInterval设置了一个200ms的时间间隔的重复定时器。从以上代码可以看出事件处理程序花了300ms多的时间完成,而定时器代码也花了300ms的时间,这个时候就会出现跳过间隔且连续两次运行定时器代码的情况。请看下图:

  

  上图中,第一个定时器在205ms出添加到队列中的,但是直到过了300ms才能够执行。当执行定时器代码时,在405ms时有一个定时器代码实例被添加到等待队列中。在605ms处第一个定时器代码仍然在运行,同时在代码队列中已经有了另一个定时器的代码实例。所以在这个时间点上的定时器代码不会被添加到队列中。结果在205ms处添加的定时器代码执行完毕后,405ms处添加的定时器代码会立即执行。

  所以在使用setInterval做动画时要注意两个问题:

  1. 不能使用固定步长作为做动画,一定要使用百分比: 开始值 + (目标值 - 开始值) * (Date.now() - 开始时间)/ 时间区间
  2. 如果主进程运行时间过长,会出现跳帧的现象

  为了避免setInterval的两个缺点,可以使用链式setTimeout():

setTimeout(function(){
    //其他处理
    setTimeout(arguments.callee, interval);
}, interval);

  以上文章内容主要来自《Javascript高级程序设计》

时间: 2024-10-10 23:35:17

Javascript定时器学习笔记的相关文章

JavaScript闭包学习笔记

原文:JavaScript闭包学习笔记 闭包(closure)是JavaScript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现. 下面就是我的学习笔记,对于JavaScript初学者应该是很有用的. 一.变量的作用域 要理解闭包,首先必须理解JavaScript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. JavaScript语言的特殊之处,就在于函数内部可以直接读取全局变量. 1 var n=999; 2 3 function f1() { 4 alert

javascript面向对象学习笔记(二)——创建对象

javascript面向对象学习笔记(二)--创建对象 工厂模式 该模值抽象了创建具体对象de过程.用函数来封装噫特定接口创建对象的细节. function createPerson(name,age,job){ var o=new Object(); o.name=name; o.age=age; o.job=job; o.sayName=function(){ alert(this.name); }; return o; } var person1=createPerson("Chiaki&

JavaScript正则表达式学习笔记之一 - 理论基础

自从年前得空写了两篇文章之后就开始忙了,这一忙就是2个月??.当时信誓旦旦说的定期写篇博客的计划也就泡汤了??,不过好在最近有空,顺便总结一下这两个月遇到的几个问题.第一个问题就是项目中用到了一些正则才发现之前被自己忽略的正则是时候补一补了.恰逢今天周六??,就把自己学习JavaScript正则表达式的笔记整理成文,写了这篇关于正则表达式理论基础的文章,希望本文能对有需要的同学提供帮助.号外:本文相对基础,大神请忽略??. 一. 基本概念 正则表达式是用于匹配字符串中字符组合的模式. 一种几乎可

Javascript MVC 学习笔记(一) 模型和数据

写在前面 最近在看<MVC的Javascript富应用开发>一书,本来是抱着一口气读完的想法去看的,结果才看了一点就傻眼了:太多不懂的地方了.只好看一点查一点,一点一点往下看吧,进度虽慢但也一定要坚持看完.本学习笔记是对书上所讲解内容的理解和记录. 笔记里的代码大多会按书上摘录下来,因为<MVC的Javascript富应用开发>是结合了JQuery库,所以对于JQuery中不太懂的知识点也会附在代码后面,也算是一些额外的收获. MVC概述 要学习MVC,首先得知道MVC是什么,MV

JavaScript正则表达式-学习笔记(不定期更新)

JavaScript权威指南学习笔记,禁止转载! 8.正则表达式 在常见的字符串检索或替换中,我们需要提供一种模式表示检索或替换的规则. 正则表达式使用单个字符串来描述.匹配一系列符合某个句法规则的字符串. 使用: /\d\d\d/.test("123");  //true new RegExp("Bosn").test("Hi,Bosn");  //true 正则基础: . 任何字符(除换行符以外) /-/.test('[email prote

JavaScript对象-学习笔记

JavaScript权威指南学习笔记,禁止转载! 5.对象 对象的属性是无序的,每个属性都有一个字符串key和值value, 数据属性的标签:writable.enumerable.configurable.value 访问器属性的标签:enumerable.configurable.get.set.get表示属性可读,set表示属性可写.属性前面有下划线表示只能通过对象方法get/set访问的属性,也就是访问器属性. (1)创建对象 1)字面量var obj={x:1,y:2}; 2)new:

《高性能JavaScript》学习笔记——日更中

------------------7-20更------------------ 最近在看<高性能JavaScript>一书,里面当中,有讲很多提高js性能的书,正在看的过程中,记下做法以及原因,供以后学习参考: 1.将经常使用的对象成员.数组项.和域外变量存入局部变量 原因:数据存储位置对大地代码整体性能会产生重要的影响,直接变量和局部变量的访问速度快于数组和对象成员.因为局部变量位于作用域链的第一个对象中,全局变量位于作用域链的最后一环.变量在作用域链的位置越深,访问的时间就越长. 1

阮一峰老师JavaScript课程学习笔记

1.switch采用的是严格相等运算符 2.break和continue都具有跳转作用,break语句跳出循环,continue用于立即终止本轮循环,返回循环结构的头部,开始下一轮循环. 3.JavaScript内部所有数字都是以64位浮点数形式存储,涉及小数的运算和比较需要特别小心. (-1)^符号位 * 1.xx...xx * 2^指数位 4.NaN是JavaScript的特殊值,表示"非数字(Not a Number)",主要出现在将字符串解析成数字出错的场合.NaN不等于任何值

JavaScript新手学习笔记1——数组

今天,我复习了一下JavaScript的数组相关的知识,总结一下数组的API: 总共有11个API:按照学习的先后顺序来吧,分别是: ① toString()  语法:arr.toString(); 将数组转化为字符串,并且返回这个字符串,以逗号分隔:但是不改变原数组: 1 var arr=[1,2,3,4,5]; 2 var result=arr.toString(); 3 console.log(result); //1,2,3,4,5 4 console.log(arr); //[1,2,