引言

  使用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. Java多线程有哪几种实现方式? Java中的类如何保证线程安全? 请说明ThreadLocal的用法和适用场景

    java的同步机制,大概是通过:1.synchronized:2.Object方法中的wait,notify:3.ThreadLocal机制来实现的, 其中synchronized有两种用法:1.对类 ...

  2. 【POJ 2406】Power Strings(KMP循环节)

    终于靠着理解写出KMP了,两种KMP要代码中这种才能求循环节.i-next[i]就是循环节. #include<cstdio> #define N 1000005 char s[N]; i ...

  3. webuploader跨域上传

    浏览器在跨域请求前会发个options请求来验证是否跨域,所以后端再处理这个options请求时,要告诉浏览器一些信息. 也就是个header信息 header("Access-Contro ...

  4. Thinking in java学习笔记之垃圾回收器如何工作

    垃圾回收器使得java在堆上分配空间的速度可以和其他语言从堆栈上分配空间的速度媲美.

  5. golang学习之旅:官方文档汇总

    The Go Programming Language Specification:http://localhost:8080/ref/spec学习Constants.Variables.Types. ...

  6. 【BZOJ-1568】Blue Mary开公司 李超线段树 (标记永久化)

    1568: [JSOI2008]Blue Mary开公司 Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 557  Solved: 192[Submit ...

  7. 针对CMS中的tag标签理解

    针对CMS的tag标签有以下解释: 什么tag标签? TAG标签是一种由自定义的一种标签,要比分类更加的准确,可以概括文章主要内容的关键词. 运用TAG标签,可以使网站的文章更容易被搜索引擎检索到.百 ...

  8. Jenkins的Publish Over FTP Plugin插件参数使用

    无论在Windows还是Linux下,都是采用这样方式${WORKSPACE}

  9. django 快速搭建blog

    如果本文看不懂的,去看的我视频吧!http://www.testpub.cn/ ------------------------------------------- Django 自称是“最适合开发 ...

  10. 用DOS命令打开IE浏览器、我的文档等等

    用DOS命令打开IE浏览器 在“start”-运行中直接输入网址就可以了.如输入百度: http://www.baidu.com Command:[ start  http://www.baidu.c ...