说说 JavaScript 计时器的工作原理

原文:John Resig   http://ejohn.org/blog/how-javascript-timers-work/

How JavaScript Timers Work

 

从基础的层面来讲,理解JavaScript的定时器是如何工作的是非常重要的。计时器的执行常常和我们的直观想象不同,那是因为JavaScript引擎是单线程的。我们先来认识一下下面三个函数是如何控制计时器的。

  • var id = setTimeout(fn, delay); - 初始化一个计时器,然后在指定的时间间隔后执行。该函数返回一个唯一的标志ID(Number类型),我们可以使用它来取消计时器。
  • var id = setInterval(fn, delay); - 和setTimeout有些类似,但它是连续调用一个函数(时间间隔是delay参数)直到它被取消。
  • clearInterval(id);clearTimeout(id); - 使用计时器ID(setTimeout 和 setInterval的返回值)来取消计时器回调的发生

为了理解计时器的内在执行原理,有一个重要的概念需要加以探讨:计时器的延迟(delay)是无法得到保障的。由于所有JavaScript代码是在一个线程里执行的,所有异步事件(例如,鼠标点击和计时器)只有拥有执行机会时才会执行。用一个很好的图表加以说明:

 


(点击查看大图)

 

在这个图表中有许多信息需要理解,如果完全理解了它们,你会对JavaScript引擎如何实现异步事件有一个很好的认识。这是一个一维的图标:垂直方向表示时间,蓝色的区块表示JavaScript代码执行块。例如第一个JavaScript代码执行块需要大约18ms,鼠标点击所触发的代码执行块需要11ms,等等。

由于JavaScript引擎同一时间只执行一条代码(这是由于JavaScript单线程的性质),所以每一个JavaScript代码执行块会“阻塞”其它异步事件的执行。这就意味着当一个异步事件发生(例如,鼠标点击,计时器被触发,或者Ajax异步请求)后,这些事件的回调函数将排在执行队列的最后等待执行(实际上,排队的方式根据浏览器的不同而不同,所以这里只是一个简化);

从第一个JavaScript执行块开始研究,在第一个执行块中两个计时器被初始化:一个10ms的setTimeout()和一个10ms的setInterval()。依据何时何地计时器被初始化(计时器初始化完毕后就会开始计时),计时器实际上会在第一个代码块执行完毕前被触发。但是,计时器上绑定的函数不会立即执行(不被立即执行的原因是JavaScript是单线程的)。实际上,被延迟的函数将依次排在执行队列的最后,等待下一次恰当的时间再执行。

此外,在第一个JavaScript执行块中我们看到了一个“鼠标点击”事件发生了。一个JavaScript回调函数绑定在这个异步事件上了(我们从来不知道用户什么时候执行这个(点击)事件,因此认为它是异步的),这个函数不会被立即执行,和上面的计时器一样,它将排在执行队列的最后,等待下一次恰当的时候执行。

当第一个JavaScript执行块执行完毕后,浏览器会立即问一个问题:哪个函数(语句)在等待被执行?在这时,一个“鼠标点击事件处理函数”和一个“计时器回调函数”都在等待执行。浏览器会选择一个(实际上选择了“鼠标点击事件的处理函数”,因为由图可知它是先进队的)立即执行。而“计时器回调函数”将等待下次适合的时间执行。

注意,当“鼠标点击事件处理函数”执行的时候,setInterval的回调函数第一次被触发了。和setTimeout的回调函数一样,它将排到执行队列的最后等待执行。但是,一定要注意这一点:当setInterval回调函数第二次被触发时(此时setTimeout函数仍在执行)setTimeout的第一次触发将被抛弃掉。当一个很长的代码块在执行时,可能把所有的setInterval回调函数都排在执行队列的后面,代码块执行完之后,结果便会是一大串的setInterval回调函数等待执行,并且这些函数之间没有间隔,直到全部完成。所以,浏览器倾向于的当没有更多interval的处理函数在排队时再将下一个处理函数排到队尾(这是由于间隔的问题)。

我们能够发现,当第三个setInterval回调函数被触发时,之前的setInterval回调函数仍在执行。这就说明了一个很重要的事实:setInterval不会考虑当前正在执行什么,而把所有的堵塞的函数排到队列尾部。这意味着两次setInterval回调函数之间的时间间隔会被牺牲掉(缩减)。

最后,当第二个setInterval回调函数执行完毕后,我们可以看到没有任何程序等待JavaScript引擎执行了。这就意味着浏览器现在在等待一个新的异步事件的发生。在50ms时一个新的setInterval回调函数再次被触发,这时,没有任何的执行块阻塞它的执行了。所以它会立刻被执行。

让我们用一个例子来阐明setTimeoutsetInterval之间的区别:

setTimeout(function(){
    /* Some long block of code... */
    setTimeout(arguments.callee, 10);
  }, 10);
  
  setInterval(function(){
    /* Some long block of code... */
  }, 10);

这两句代码乍一看没什么差别,但是它们是不同的。setTimeout回调函数的执行和上一次执行之间的间隔至少有10ms(可能会更多,但不会少于10ms),而setInterval的回调函数将尝试每隔10ms执行一次,不论上次是否执行完毕。

在这里我们学到了很多知识,总结一下:

  • JavaScript引擎是单线程的,强制所有的异步事件排队等待执行
  • setTimeout 和 setInterval 在执行异步代码的时候有着根本的不同
  • 如果一个计时器被阻塞而不能立即执行,它将延迟执行直到下一次可能执行的时间点才被执行(比期望的时间间隔要长些)
  • 如果setInterval回调函数的执行时间将足够长(比指定的时间间隔长),它们将连续执行并且彼此之间没有时间间隔。

上述这些知识点都是非常重要的。了解了JavaScript引擎是如何工作的,尤其是大量的异步事件(连续)发生时,才能为构建高级应用程序打好基础。

转载于:https://www.cnblogs.com/zhepama/archive/2013/05/14/3077048.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/474406.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode 1538. Guess the Majority in a Hidden Array

文章目录1. 题目2. 解题1. 题目 We have an integer array nums, where all the integers in nums are 0 or 1. You will not be given direct access to the array, instead, you will have an API ArrayReader which have the following functions: int query(int a, int b…

LeetCode 1258. 近义词句子(哈希+并查集+排序+回溯)

文章目录1. 题目2. 解题1. 题目 给你一个近义词表 synonyms 和一个句子 text , synonyms 表中是一些近义词对 ,你可以将句子 text 中每个单词用它的近义词来替换。 请你找出所有用近义词替换后的句子,按 字典序排序 后返回。 示例 1&#…

LeetCode 1066. 校园自行车分配 II(状态压缩DP)

文章目录1. 题目2. 解题2.1 回溯超时2.2 状态压缩DP1. 题目 在由 2D 网格表示的校园里有 n 位工人&#xff08;worker&#xff09;和 m 辆自行车&#xff08;bike&#xff09;&#xff0c;n < m。所有工人和自行车的位置都用网格上的 2D 坐标表示。 我们为每一位工人分配一…

Bootstrap(二)—格栅系统!

W(A*n)-i W是一个页面的总宽度&#xff0c;比如950px&#xff1b;而A代表一个版块的宽度&#xff0c;设置为apx&#xff1b;n就是分为几个版块&#xff1b;而i就是区块之间的间隔。 例如 950&#xff08;a*24&#xff09;-10 而a40px&#xff1b;改变A和i的值就会生成不同的布…

LeetCode 625. 最小因式分解(贪心)

文章目录1. 题目2. 解题1. 题目 给定一个正整数 a&#xff0c;找出最小的正整数 b 使得 b 的所有数位相乘恰好等于 a。 如果不存在这样的结果或者结果不是 32 位有符号整数&#xff0c;返回 0。 样例 1 输入&#xff1a; 48 输出&#xff1a; 68样例 2 输入&#xff1a; 15…

u盘无法显示在计算机,插进电脑就是不认 不显示盘符的U盘是闹哪样?

唉&#xff0c;本来今天想和大家聊聊Windows 10春季创意者更新有啥好玩的东西&#xff0c;外加有哪些大坑需要注意和避免&#xff0c;结果微软跳票了&#xff0c;以下就省略下千字的小编内心独白吧。每次大版本的Windows更新对懒人或者对电脑来说&#xff0c;是个绝佳清理电脑的…

LeetCode 582. 杀死进程(图的遍历)

文章目录1. 题目2. 解题2.1 DFS2.2 BFS1. 题目 给 n 个进程&#xff0c;每个进程都有一个独一无二的 PID &#xff08;进程编号&#xff09;和它的 PPID &#xff08;父进程编号&#xff09;。 每一个进程只有一个父进程&#xff0c;但是每个进程可能会有一个或者多个孩子进程…

LeetCode 737. 句子相似性 II(并查集)

文章目录1. 题目2. 解题1. 题目 给定两个句子 words1, words2 &#xff08;每个用字符串数组表示&#xff09;&#xff0c;和一个相似单词对的列表 pairs &#xff0c;判断是否两个句子是相似的。 例如&#xff0c;当相似单词对是 pairs [["great", "fine&qu…

计算机硬盘怎么设置ntfs,每次设置系统后,能否更改计算机硬盘分区的fat32和ntfs格式?...

f3622635硬盘的格式转换一个&#xff0c;FAT32到NTFS在“运行”中输入“ CMD”以打开“命令提示符”窗口&#xff0c;输入: “ CONVERT F: / FS: NTFS”&#xff0c;其中“ F: ”是分区驱动器号(带冒号)&#xff0c;“ / FS: NTFS“是将指定的分区转换为NTFS格式.我认为它会很快…

LeetCode 708. 循环有序列表的插入

文章目录1. 题目2. 解题1. 题目 给定循环升序列表中的一个点&#xff0c;写一个函数向这个列表中插入一个新元素&#xff0c;使这个列表仍然是循环升序的。 给定的可以是这个列表中任意一个顶点的指针&#xff0c;并不一定是这个列表中最小元素的指针。 如果有多个满足条件的…

VMWare serve 2.0 进入 RHEL Linux rescue模式

可能由于我的鼠标点击速度比较慢所以一直没机会在 VMware Serve启动的时候按F2进入bios 模式&#xff0c;哈哈。 1.在次用另外一种方式&#xff1a; 2.进入bios 系统后&#xff0c;选择“boot”&#xff0c;再选"CD/ROM"&#xff0c;上移到第一位。 3.在boot:后面输入…

LeetCode 755. 倒水(模拟)

文章目录1. 题目2. 解题1. 题目 给出一个地形高度图&#xff0c; heights[i] 表示该索引处的高度。 每个索引的宽度为 1。在 V 个单位的水落在索引 K 处以后&#xff0c;每个索引位置有多少水&#xff1f; 水最先会在索引 K 处下降并且落在该索引位置的最高地形或水面之上。然…

LeetCode 444. 序列重建(拓扑排序)

文章目录1. 题目2. 解题1. 题目 验证原始的序列 org 是否可以从序列集 seqs 中唯一地重建。 序列 org 是 1 到 n 整数的排列&#xff0c;其中 1 ≤ n ≤ 104。 重建是指在序列集 seqs 中构建最短的公共超序列。&#xff08;即使得所有 seqs 中的序列都是该最短序列的子序列&am…

华硕主板如何用u盘启动计算机,华硕主板怎么设置u盘启动都有哪些方法

随着互联网的不断发展&#xff0c;现在使用电脑的机会越来越多了。但是机器难免出故障&#xff0c;或者对于新的电脑需要设置启动。那么华硕主板怎么设置u盘启动。下面由一键工作室介绍一下。华硕主板怎么设置u盘启动华硕主板怎么设置u盘启动 华硕主板设置u盘启动方法1、首先&a…

LeetCode 353. 贪吃蛇(deque+set)

文章目录1. 题目2. 解题1. 题目 请你设计一个 贪吃蛇游戏&#xff0c;该游戏将会在一个 屏幕尺寸 宽度 x 高度 的屏幕上运行。 起初时&#xff0c;蛇在左上角的 (0, 0) 位置&#xff0c;身体长度为 1 个单位。 你将会被给出一个 (行, 列) 形式的食物位置序列。当蛇吃到食物…

计算机简单故障时的排除方法,电脑简单故障排除解决办法大全

电脑简单故障排除解决办法大全一、电脑罢 工了?听报警声就可以处理故障!在使用电脑的时候&#xff0c;我们会经常遇到开机时电脑黑屏没有反应的情况&#xff0c;普通的电脑用户而对这样的故障实在是无从下手&#xff0c;但是一般电脑会有一个内部自检的功能&#xff0c;如果检…

LeetCode MySQL 1543. Fix Product Name Format(trim去空格+upper/lower大小写)

文章目录1. 题目2. 解题1. 题目 Table: Sales ----------------------- | Column Name | Type | ----------------------- | sale_id | int | | product_name | varchar | | sale_date | date | ----------------------- sale_id is the primary key for …

云计算之路-阿里云上:拔云见日的那一刻,热泪盈眶

当用路过秋天的压力测试工具重现问题的那一刻&#xff0c;热泪盈眶&#xff01;这段时间所承受的一切一涌而出。。。 下面这张图是首次压力测试重现问题时的Windows性能监视器截图&#xff0c;我们对这样的图太熟悉了&#xff0c;当它一出现&#xff0c;就知道问题重现了。红色…