浅谈JavaScript中的定时器
引言
使用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中的定时器的更多相关文章
- 浅谈JavaScript中的闭包
浅谈JavaScript中的闭包 在JavaScript中,闭包是指这样一个函数:它有权访问另一个函数作用域中的变量. 创建一个闭包的常用的方式:在一个函数内部创建另一个函数. 比如: functio ...
- 浅谈JavaScript中的null和undefined
浅谈JavaScript中的null和undefined null null是JavaScript中的关键字,表示一个特殊值,常用来描述"空值". 对null进行typeof类型运 ...
- 浅谈JavaScript中的正则表达式(适用初学者观看)
浅谈JavaScript中的正则表达式 1.什么是正则表达式(RegExp)? 官方定义: 正则表达式是一种特殊的字符串模式,用于匹配一组字符串,就好比用模具做产品,而正则就是这个模具,定义一种规则去 ...
- 浅谈JavaScript中的内存管理
一门语言的内存存储方式是我们学习他必须要了解的,接下来让我浅谈一下自己对他的认识. 首先说,JavaScript中的变量包含两种两种类型: 1)值类型或基本类型:undefined.null.numb ...
- 通过一道笔试题浅谈javascript中的promise对象
因为前几天做了一个promise对象捕获错误的面试题目,所以这几天又重温了一下promise对象.现在借这道题来分享下一些很基础的知识点. 下面是一个面试题目,三个promise对象捕获错误的例子,返 ...
- 浅谈JavaScript中闭包
引言 闭包可以说是JavaScript中最有特色的一个地方,很好的理解闭包是更深层次的学习JavaScript的基础.这篇文章我们就来简单的谈下JavaScript下的闭包. 闭包是什么? 闭包是什么 ...
- 浅谈JavaScript中的继承
引言 在JavaScript中,实现继承的主要方式是通过原型链技术.这一篇文章我们就通过介绍JavaScript中实现继承的几种方式来慢慢领会JavaScript中继承实现的点点滴滴. 原型链介绍 原 ...
- 浅谈JavaScript中继承的实现
谈到js中的面向对象编程,都有一个共同点,选择原型属性还是构造函数,两者各有利弊,而就片面的从js的对象创建以及继承的实现两个方面来说,官方所推荐的是两个相结合,各尽其责,各取其长,在前面的例子中,我 ...
- 【总结】浅谈JavaScript中的接口
一.什么是接口 接口是面向对象JavaScript程序员的工具箱中最有用的工具之一.在设计模式中提出的可重用的面向对象设计的原则之一就是“针对接口编程而不是实现编程”,即我们所说的面向接口编程,这个概 ...
随机推荐
- asp.net mvc 依赖缓存启动项配置
msdn 参考地址:https://msdn.microsoft.com/zh-cn/library/ms229862 4.5 第一步:32bit%windir%\Microsoft.NET\Fram ...
- double截取小数点位数
(double)decimal.Round(decimal.Parse((planVoSt.TotalCompleteAmount / planVoSt.TotalUserCount).ToStrin ...
- 又爱又恨系列之枚举enum
其实枚举挺简单的,只不过以前没好好学,所以不知道这个东西,恩,现在梳理一下 整体而言,首先枚举是一个数据类型,这个数据类型和结构体有点像 可以分为三个层次 1.枚举数据类型定义 第一种:enum 枚举 ...
- 77.Android之代码混淆
转载:http://www.jianshu.com/p/7436a1a32891 简介 作为Android开发者,如果你不想开源你的应用,那么在应用发布前,就需要对代码进行混淆处理,从而让我们代码即使 ...
- BZOJ 4384: [POI2015]Trzy wieże
4384: [POI2015]Trzy wieże Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 217 Solved: 61[Submit][St ...
- Leetcode First Bad Version
You are a product manager and currently leading a team to develop a new product. Unfortunately, the ...
- 基于Token的身份验证——JWT
初次了解JWT,很基础,高手勿喷. 基于Token的身份验证用来替代传统的cookie+session身份验证方法中的session. JWT是啥? JWT就是一个字符串,经过加密处理与校验处理的字符 ...
- BZOJ1018 [SHOI2008]堵塞的交通traffic
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000作者博客:http://www.cnblogs.com/ljh2000-jump/转 ...
- 第一章、欢迎进入C#编程世界
1.GUI:图形用户界面. 2.在C#中,所有可执行代码都必须在方法中定义,而方法必须从属于类或结构. 3.程序集中可能包含多个命名空间的类,而一个命名空间可能跨越多个程序集. 4.解决方案文件使用. ...
- FZU 2193 So Hard (有限小数转换最简分数)(想法题)
题目链接: 传送门 So Hard Time Limit: 1000MS Memory Limit: 65536K 题目描述 请将有限小数化为最简分数. 输入 一个整数n 表示需要转化的小数个 ...