【JavaScript】JavaScript中的Timer是怎么工作的( setTimeout,setInterval)
原文(http://www.yeeyan.org/articles/view/luosheng/24380)
作为入门者来说,了解JavaScript中timer的工作方式是很重要的。通常它们的表现行为并不是那么地直观,而这是因为它们都处在一个单一线程中。让我们先来看一看三个用来创建以及操作timer的函数。
var id = setTimeout(fn, delay);- 初始化一个单一的timer,这个timer将会在一定延时后去调用指定的函数。这个函数(setTimeout)将返回一个唯一的ID,我们可以通过这个ID来取消timer。var id = setInterval(fn, delay);- 与setTimeout类似,只不过它会持续地调用指定的函数(每次都有一个延时),直到timer被取消为止。clearInterval(id);,clearTimeout(id);- 接受一个timer的ID(由上述的两个函数返回的),并且停止timer的回调事件。
要搞明白timer在内部是怎么工作的,我们还需要知道一个很重要的概念:timer的延时并不是每次都能如你所愿的。由于在同一个浏览器中所有的JavaScript都只在单一线程中执行,那些异步的事件(比如说鼠标点击,或者timer)只在执行期出现空闲的时候才会运行。这个用图最能表示清楚了,请参见下图:
在这个示例中有很多信息可以挖掘,但是完全理解了之后你将会更清楚地认识到异步的JavaScript是怎么执行的。这是个一维的图:竖直方向上的是(挂钟式)时间,单位为毫秒。蓝色的框表示正在执行的JavaScript片段。举例来说,第一块JavaScript执行了约18ms,而鼠标点击则执行了约11ms,以此类推。
由于JavaScript向来都只能在同一时间执行一块代码(这是由它单线程的本质决定的),所以每一个代码块都“阻塞”了其他的异步事件。这意味着当异步事件发生时(比如鼠标点击、timer触发或者是XMLHttpRequest完成),这些事件将进入到一个队列中等待执行(队列的实现方法因浏览器而异,我们在此只讨论一个简化的情况)。
刚开始,在第一个JavaScript块中,有两个timer被初始化了:一个10ms的setTimeout和一个是10ms的setInterval。由于timer(这里的timer指setTimeout中的timer,而下文中的interval则指setInvertal中的timer)开始的时间,实际上它在第一个代码块结束前就已经触发了。然而请注意,它并不会马上执行(事实上由于单线程的存在,它也无法做到马上执行)。相反的,这个被延期执行的函数进入队列中,等待在空闲的时候被执行。
另外,在第一个JavaScript块中,我们看到一个鼠标点击事件也发生了。而与这个异步事件(我们不知道用户什么时候会去执行一个动作,因此将其认为是一个异步动作)相关的JavaScript回调函数也无法立马执行,正如timer一样,它也进行到队列中等待被执行。
当第一个JavaScript块被执行完之后,浏览器问了一个问题:有正在等待被执行的代码吗?在这个例子中,鼠标点击事件和time事件都正在队列中等待。于是浏览器选了一个(鼠标点击事件),然后马上执行它。而timer只能继续等下去。
注意当鼠标点击事件正在执行的时候第一次的interval事件也触发了,与timer一样,它的事件也进入队列等待之后执行。然而,注意,当interval再次触发的时候(这个时候timer的事件正在执行),这一次它的事件被丢弃了。如果你在一个大的JavaScript代码块正在执行的时候把所有的interval回调函数都囤起来的话,其结果就是在JavaScript代码块执行完了之后会有一堆的interval事件被执行,而执行过程中不会有间隔。因此,取代的作法是浏览器情愿先等一等,以确保在一个interval进入队列的时候队列中没有别的interval。
事实上,我们可以在例子中看出:当第三个interval触发的时候这个interval自身正在执行。这告诉我们一个重要的事实:interval是不管当前在执行些什么的,在任何情况下它都会进入到队列中去,即使这样意味着每次回调之间的时间就不准确了。
最后,当第二个interval回调执行完后,我们可以看到队列已经被清空,没有什么需要JavaScript引擎去执行的了。这表明浏览器现在等待一个新的异步事件发生。于是在50ms的时候我们看到interval又触发了。这一样,由于没有什么东西挡住了它的执行,它马上就触发了。
让我们来看一个例子,这个例子更好地阐释了setTimeout和setInveral之间的区别。
/* 一个很长的代码块…… */
setTimeout(arguments.callee, 10);
}, 10);
setInterval(function(){
/* 一个很长的代码块…… */
}, 10);
乍看上去,这两段代码在功能上似乎是相同的,可实际上并非如此。setTimeout的代码在前一次的回调执行完后总是至少会有10ms的延时(有可能会更多,但是绝对不会更少);而setInterval则总是在每10ms的时候尝试执行一次回调,它不管上一次回调是什么时候执行的。
我们在此学到了很多,让我们重述一下:
- JavaScript引擎只有一个线程,这使得异步事件必需列队等待执行。
setTimeout和setInterval在如何执行代码上有着本质地区别。- 如果一个timer在将要执行的时候被阻塞,它将会等待下一个时机(比预期的延时要长)。
- 如果interval的执行时间较长(比指定的延时长),那么它们将连续地执行而没有延时。
以上这些知识是相当重要的。知道JavaScript引擎的工作方式,尤其是知道它在有很多异步事件发生的时候是怎么工作的,为我们在写进阶的应用程序代码打下了坚实的基础。
【JavaScript】JavaScript中的Timer是怎么工作的( setTimeout,setInterval)的更多相关文章
- js异步处理工作机制(setTimeout, setInterval)
经常谈到异步,但是发现自己一直没深入理解setTimeout, setInterval,逛论坛的时候发现了这篇好文章,分享一下. ————————————————————以下为原文—————————— ...
- javascript动画中的“帧”
在写游戏的时候,动画移动的速度需要保持一致,为了在各个软硬件环境中速度的一致,需要考虑帧频的不同. 计算时间系数: 时间系数 = 目标FPS / 实际FPS 计算实际FPS actualFPS = 1 ...
- [ Javascript ] JavaScript中的定时器(Timer) 是怎样工作的!
作为入门者来说.了解JavaScript中timer的工作方式是非常重要的.通常它们的表现行为并非那么地直观,而这是由于它们都处在一个单一线程中.让我们先来看一看三个用来创建以及操作timer的函数. ...
- JavaScript游戏中的面向对象的设计
简介: 从程序角度考虑,许多 JavaScript 都基于循环和大量的 if/else 语句.在本文中,我们可了解一种更聪明的做法 — 在 JavaScript 游戏中使用面向对象来设计.本文将概述原 ...
- JavaScript ES6中export、import与export default的用法和区别
前言 相信很多人都使用过export.export default.import,然而它们到底有什么区别呢? 在看他们之间的区别之前,我们先来看看它们的用法. ES6 import和export的用法 ...
- JavaScript jQuery 中定义数组与操作及jquery数组操作
首先给大家介绍javascript jquery中定义数组与操作的相关知识,具体内容如下所示: 1.认识数组 数组就是某类数据的集合,数据类型可以是整型.字符串.甚至是对象Javascript不支持多 ...
- JavaScript文件中调用AngularJS内部方法或改变$scope变量
需要在其他JavaScript文件中调用AngularJS内部方法或改变$scope变量,同时还要保持双向数据绑定: 首先获取AngularJS application: 方法一:通过controll ...
- JavaScript ES7 中使用 async/await 解决回调函数嵌套问题
原文链接:http://aisk.me/using-async-await-to-avoid-callback-hell/ JavaScript 中最蛋疼的事情莫过于回调函数嵌套问题.以往在浏览器中, ...
- 警惕javascript代码中的“</script>”!
之前在写<博客园自定义博客侧边栏公告的过滤漏洞>的时候遇到了一个javascript代码报错“语法错误”的问题,一直不得以解决,感谢Arliang发现了并为我进行了耐心的解释,现整理如下: ...
随机推荐
- 判断CString字符串中各位是数字,大小写字母,符号,汉字.xml
pre{ line-height:1; color:#1e1e1e; background-color:#e9e9ff; font-size:16px;}.sysFunc{color:#627cf6; ...
- 操作符重载.xml
pre{ line-height:1; color:#1e1e1e; background-color:#d2d2d2; font-size:16px;}.sysFunc{color:#627cf6; ...
- ansible服务模块和组模块使用
本篇文章主要是介绍ansible服务模块和组模块的使用. 主要模块为ansible service module和ansible group moudle,下面的内容均是通过实践得到,可以直接运行相关 ...
- Epic - Decimal Number
Let the user enter a decimal number. Therange allowed is 0.0001 to 0.9999. Only four decimal places ...
- To follow the path
look to the master, follow the master, walk with the master, see through the master, bec ...
- how to install flash
Choice 1: Install Flash from Repository: This is fairly simple and easy and should work from most p ...
- asp.net mvc让我告诉你请求从哪里来
移动互联网的兴起,导致越来越多的网站开始看中自己的mobile站点(m站),例如我们用手机浏览器访问58,美团等网站都会看到适配的m站点,随之而来响应式布局,h5等技术随之兴起,对于一些大型网站来说, ...
- Maven常用插件参数
1.clean: 清理默认路径以外的文件 <build> [...] <plugin> <artifactId>maven-clean-plugin</art ...
- 转】mysql数据库delete数据时不支持表别名
原博文出自于: http://www.cnblogs.com/xdp-gacl/p/4012853.html 感谢! 今天在帮同事查看一条删除的SQL语句执行出错的问题 SQL语句如下: 1 DELE ...
- 让CSS3给你的文字加上边框宽度,并实现镂空效果
这次,我主要向大家介绍一下CSS3下的-webkit-text-stroke属性,并分享几个用该属性制作的镂空文字效果. 1.-webkit-text-stroke属性简介 CSS边框的一个不足就是只 ...
