引言

  使用setTimeout()和setInterval()创建的定时器可以实现很多有意思的功能。很多人认为定时器是一个单独的线程(之前我也是),但是JavaScript是运行在单线程环境中的,而定时器只是计划代码在未来的某个时间执行。执行时间是不能保证的,在页面的生命周期中,会不断有其他的代码在控制着JavaScript的执行主线程。比如:在页面下载完成以后的JavaScript代码需要执行、事件处理函数、Ajax的回调函数都需要通过主线程来执行。浏览器只负责排序,指定某一段代码在某一时刻需要被执行。

  下面我们通过一个例子来详细的了解下。

  我们可以把JavaScript想象成在时间线上执行的。例如:页面刚加载时,首先执行的是包含在<script>元素中的代码,这通常是一些简单的函数声明和变量的初始化。在这时候,JavaScript主线程就会等待更多代码执行。当线程空闲的时候,下一段代码会被触发并立即执行。这样一个页面的时间线类似于下图:

  在这张图片中,我们可以生动的看到JavaScript主线程的执行机制。其实,在JavaScript主线程之外,还有一个保存下一个即将被执行的代码的队列存在。随着页面在其生命周期中推移,代码会按照执行顺序放入队列,并在未来的某一个时间执行代码。例如:当接收到某一个Ajax响应时,其回调函数会被放入队列中。在JavaScript中是没有任务代码能立即执行的,但是一旦主线程空闲,队列中的代码会被立即执行。

  定时器对于队列的工作方式是这样的:当特定时间过去后,将定时器代码插入到队列中。注意:给队列添加代码不会意味着立即执行,只是表示会尽快执行。例如:我们在定时器中设定延时200毫秒。并不是意味着200毫秒以后需代码一定会执行。只是200毫秒以后这段代码会被添加到执行队列中。如果此时执行队列为空,那么代码会被立即执行。其他情况下代码可能需要等待更长的时间来执行。

  请看下面的代码:

 var btn = document.getElementById("btn");
btn.onclick = function () {
setTimeout(function () {
alert("Hello");
}, 250);
//其他代码.....
}

  在代码中,我们给按钮添加了事件处理程序。事件处理程序设置了一个250毫秒以后执行的定时器。点击按钮后,首先进入执行队列的是onclick事件处理函数。再过250毫秒以后,定时器的代码才会被添加到执行队列中。如果我们假设前面的onclick事件处理函数需要执行300毫秒,那么定时器代码至少需要300毫秒一以后才会执行(因为300毫秒以后JavaScript主线程执行完事件处理函数后,空闲状态,可以立即执行定时器的代码)。下面我们画一张时序图来形象的描述下这个过程。如图:

  

  在图片中我看到,在255毫秒的时候定时器代码被添加到执行队列了。但是此时还无法运行。因为主线程在执行事件处理函数。当主线程空闲后,会立即执行定时器代码。

  重复的定时器

  使用setInterval定时器可以保证定时器代码规则的插入队列中。但是这是有问题的。比如:定时器代码可能在代码再次被添加到队列之前还没有执行完毕,结果导致定时器代码连续运行好几次,之间没有任何停顿。不过现代的JavaScript引擎可以避免这种问题。不过这种重复定时器的规则还是有两个弊端。

  1、某些间隔会被跳过。

  2、多个定时器的代码执行之间的间隔可能比预期的小。

  假设某一个事件处理程序使用setInterval设置了一个200毫秒的重复定时器。如果事件处理程序需要300多毫秒才执行完毕,同时定时器代码页花了差不多时间,那么就会跳过一个定时器间隔,因为前一个定时器的代码还没有执行完毕。请看下图:

  我们看这张图,我们看到在5毫秒的时候我们创建了重复的定时器,在205毫秒的时候,队列中添加了第一个定时器代码。但是事件处理程序需要300多毫秒才会执行完毕。事件处理函数执行完毕以后,主线程立即执行队列中的定时器代码。在400多毫秒的时候,第二个定时器代码被添加到队列中。但是单到了600多毫秒时,第三个定时器代码会被跳过,因为当前执行队列存在未执行的代码(第二个定时器代码)。

  解决方案

 setTimeout(function(){
//处理代码
setTimeout(argument.callee,interval);
},interval);

  在这段代码中,我们使用了链式调用setTimeout()模式。每一次函数调用都会重新创建一个新的定时器。第二个setTimeout函数使用了argument.callee来获取当前执行函数的引用,并且设置了另一个新的定时器。这样做的好处是:在前一个定时器代码执行之前,不会往队列中添加新的定时器代码,不会存在任何间隔。同时也可以保证在下一次定时器代码执行之前,至少需要等待一段时间(interval的值),避免了连续执行。

浅谈JavaScript中的定时器的更多相关文章

  1. 浅谈JavaScript中的闭包

    浅谈JavaScript中的闭包 在JavaScript中,闭包是指这样一个函数:它有权访问另一个函数作用域中的变量. 创建一个闭包的常用的方式:在一个函数内部创建另一个函数. 比如: functio ...

  2. 浅谈JavaScript中的null和undefined

    浅谈JavaScript中的null和undefined null null是JavaScript中的关键字,表示一个特殊值,常用来描述"空值". 对null进行typeof类型运 ...

  3. 浅谈JavaScript中的正则表达式(适用初学者观看)

    浅谈JavaScript中的正则表达式 1.什么是正则表达式(RegExp)? 官方定义: 正则表达式是一种特殊的字符串模式,用于匹配一组字符串,就好比用模具做产品,而正则就是这个模具,定义一种规则去 ...

  4. 浅谈JavaScript中的内存管理

    一门语言的内存存储方式是我们学习他必须要了解的,接下来让我浅谈一下自己对他的认识. 首先说,JavaScript中的变量包含两种两种类型: 1)值类型或基本类型:undefined.null.numb ...

  5. 通过一道笔试题浅谈javascript中的promise对象

    因为前几天做了一个promise对象捕获错误的面试题目,所以这几天又重温了一下promise对象.现在借这道题来分享下一些很基础的知识点. 下面是一个面试题目,三个promise对象捕获错误的例子,返 ...

  6. 浅谈JavaScript中闭包

    引言 闭包可以说是JavaScript中最有特色的一个地方,很好的理解闭包是更深层次的学习JavaScript的基础.这篇文章我们就来简单的谈下JavaScript下的闭包. 闭包是什么? 闭包是什么 ...

  7. 浅谈JavaScript中的继承

    引言 在JavaScript中,实现继承的主要方式是通过原型链技术.这一篇文章我们就通过介绍JavaScript中实现继承的几种方式来慢慢领会JavaScript中继承实现的点点滴滴. 原型链介绍 原 ...

  8. 浅谈JavaScript中继承的实现

    谈到js中的面向对象编程,都有一个共同点,选择原型属性还是构造函数,两者各有利弊,而就片面的从js的对象创建以及继承的实现两个方面来说,官方所推荐的是两个相结合,各尽其责,各取其长,在前面的例子中,我 ...

  9. 【总结】浅谈JavaScript中的接口

    一.什么是接口 接口是面向对象JavaScript程序员的工具箱中最有用的工具之一.在设计模式中提出的可重用的面向对象设计的原则之一就是“针对接口编程而不是实现编程”,即我们所说的面向接口编程,这个概 ...

随机推荐

  1. windows下为mysql添加日志

    mysql的配置文件 [mysqld] …… log-error="D:/phpStudy/log/mysql/mysql_log_err.txt" log="D:/ph ...

  2. 【bzoj2286】 消耗战

    http://www.lydsy.com/JudgeOnline/problem.php?id=2286 (题目链接) 一个小小的细节,WA了一天,欲哭无泪了.. 题意 给出一个n个节点的带权树,总共 ...

  3. Hash_bzoj1862: [Zjoi2006]GameZ游戏排名系统

    #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #i ...

  4. [NOIP2012] 提高组 洛谷P1080 国王游戏

    题目描述 恰逢 H 国国庆,国王邀请 n 位大臣来玩一个有奖游戏.首先,他让每个大臣在左.右 手上面分别写下一个整数,国王自己也在左.右手上各写一个整数.然后,让这 n 位大臣排 成一排,国王站在队伍 ...

  5. django数据库时间存储格式问题

    http://blog.csdn.net/ichuzhen/article/details/38555645 一般建议用datefield 关于从数据库读取出来格式问题可以看 http://stack ...

  6. Linux以外的开源操作系统大汇总

    开源操作系统即公开源代码的操作系统软件,它遵循开源协议使用.编译和发布.自由和开放源代码软件中最著名的是Linux,它是一种类Unix的操作系统.Linux可安装在各种计算机硬件设备中,比如手机.平板 ...

  7. 今天执行grep命令差点把服务器搞崩

    grep "rst" -r ./ >> a.log 今天执行这个命令差点把服务器搞崩了. 本意是查找所有源代码文件中含有rst字符串的行,打印到文件a.log中,然后进 ...

  8. jquery selector 基础

    转自:http://www.cnblogs.com/zwl12549/archive/2008/08/09/1264163.html query的这套选择符是比较帅气的,借用了XPath2.0和CSS ...

  9. 深入JVM-垃圾收集器常用的GC参数

    1.与串行回收器相关的参数 -XX:+UseSerialGC:在新生代和老年代使用串行收集器 -XX:SurvivorRatio:设置eden区大小和survivor区大小的比例 -XX:Preten ...

  10. awk多模式匹配

    awk -F ':' '{if(($1 ~/wlan/)||( $1 ~/Cell/)||($1 ~/Quality*/)) {print $0}}'