【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发现了并为我进行了耐心的解释,现整理如下: ...
随机推荐
- 《学习OpenCV》中求给定点位置公式
假设有10个三维的点,使用数组存放它们有四种常见的形式: ①一个二维数组,数组的类型是CV32FC1,有n行,3列(n×3) ②类似①,也可以用一个3行n列(3×n)的二维数组 ③④用一个n行1列(n ...
- 初学JavaScript(入门一)
javaScript是世界上最流行的脚本语言 在我们的手机.电脑设备上所浏览的所有网页,以及基于HTML5手机App的交互都是通过javaScript驱动的,所以javascript是前端工作的一 ...
- Python中的并发编程
简介 我们将一个正在运行的程序称为进程.每个进程都有它自己的系统状态,包含内存状态.打开文件列表.追踪指令执行情况的程序指针以及一个保存局部变量的调用栈.通常情况下,一个进程依照一个单序列控制流顺序执 ...
- 哈希(Hash)与加密(Encrypt)的基本原理、区别及工程应用
0.摘要 今天看到吉日嘎拉的一篇关于管理软件中信息加密和安全的文章,感觉非常有实际意义.文中作者从实践经验出发,讨论了信息管理软件中如何通过哈希和加密进行数据保护.但是从文章评论中也可以看出很多朋友对 ...
- XE8 hash
c++builder xe8 hash calc md5.sha256.sha384.sha512 file and string sha256.sha384.sha512 must call l ...
- 细说OpenSessionInView问题
[环境参数] 环境:SSH框架 [问题描述] NoSession问题 HibernateTemplate对象提供的方法如果使用“延迟加载”,Session对象的管理不受开发者控制,此时如果在表现层获 ...
- LeetCode100:Same Tree
Given two binary trees, write a function to check if they are equal or not. Two binary trees are con ...
- Guid函数
使用GUID函数可以得到一个不重复的序列号,但是考虑到会出现并发等一系列情况,所以建议使用时间+GUID的方法去生成一串序列号 ,一般语法如下: string str = System.Guid.Ne ...
- Computational Geometry Template_Polygon
#include <stdlib.h> #include <math.h> #include <iostream> #define MAXN 1000 #defin ...
- ASP.NET验证控件RegularExpressionValidator的常见表达式
可以输入非0和0开头的数字:“^(0*[1-9][0-9]*|[1-9][0-9]*)$”只能输入数字:“^[0-9]*$”只能输入n位的数字:“^\d{n}$”只能输入至少n位数字:“^\d{n,} ...