JavaScript的定时器是如何工作的
理解JavaScript定时器工作原理对于学习JavaScript非常重要。因为JavaScript是单线程运行的,定时器使用场合少,不是很直观。下面通过三个函数来学习JavaScript如何定义,操作及销毁一个定时器。
- var id = setTimeout(fn, delay); - 定义一个定时器,在指定时间delay后调用函数fn。函数返回一个唯一的标识ID,如果不需要使用这个定时器可以用这个取消。
- var id = setInterval(fn, delay);- 类似setTimeout,但是会每隔指定时间delay调用指定函数fn,直至取消这个定时器。
- clearTimeout(id);clearInterval(id); -这两个函数接受一个标识ID(分别对应上面两个函数返回的ID),停止定时器的回调。
要理解定时器如何工作,首先要弄清楚一个概念,定时器的回调函数不能保证在指定时间delay一定执行。由于浏览器中的所有JavaScript都在单线程上执行,因此异步事件(例如鼠标单击和计时器)仅在执行中存在同步时间执行完有空缺时才运行。参考下图:
这张图里面包含很多信息,要想理解他们需要首先理解JavaScript异步运行机制。这张图中垂直方向上有时间刻度,以毫秒为单位,蓝色部分表示正在执行的JavaScript事件。例如,第一块JavaScript执行大约18毫秒,Mouse Click Callback大约执行11毫秒,后面以此类推。
由于JavaScript是单线程的,不能同时执行两段JavaScript代码,所以上面的蓝色的”块“都是在上一个块执行完才能执行下一个块。这意味这当一个异步任务(例如,点击鼠标事件,定时器,ajax访问)出现的时候,它将被放入到异步队列(放入队列的方式和浏览器有关,不同浏览器有不同的实现)并随后执行。
首先,在第一个代码块中,JavaScript代码中首先出先两个定时器:10ms Timer starts,10ms Interval starts。这两个定时器的回调函数何时执行取决于第一个代码块的所有代码何时执行完。请注意,由于单线程的原因,它不会立即执行。
同时,在第一个代码块里,还有一个鼠标事件Mouse Click Occurs,和上面的定时器一样,这个异步事件(点击鼠标这种用户交互是异步执行的,因为JavaScript不知道用户什么时候会点击鼠标)的回调不会立即执行,而是放在异步队列里排队等待执行。
在初始的代码块执行完毕之后,浏览器随即开始轮询这个异步队列:有那些操作等待着被执行呢?在这个例子中,鼠标点击。浏览器会选择一个立即执行(这里是鼠标点击的回调时间)。定时器会等待指定的时间delay,然后执行。
注意点击鼠标回调事件在第一个事件循环,定时器回调在随后的循环中处理。但是,在后面的事件循环中(在执行定时器处理程序时),setTimeout定时器回调函数就会被抛弃,不再执行了。如果在多个定时器之后有一大段同步任务执行,则同步任务执行完之后这些定时器回调会被立即执行,没有延迟(这个延迟可能很小,就是事件循环的间隔),直至完成。浏览器倾向于等到没有更多的异步任务被加入到异步任务队列中再开始执行。
实际上,我们可以看到在事件循环本身正在执行的同时触发了第三个回调的情况。 这向我们显示了一个重要的事实:事件循环不关心当前正在执行的内容,它们会不加区分地排队,即使这意味着从触发事件,到满足条件执行回调函数之间,有一部分事件被浪费掉了。
最后,在第二个事件回调完成执行之后,我们可以看到JavaScript引擎没有执行的剩余内容。 这意味着浏览器现在等待新的异步事件发生。 当间隔再次触发时,我们在50ms处获得此值。 但是,这次没有任何任务阻止它的执行,因此它自己立即触发。
让我们看一个示例,以更好地说明setTimeout和setInterval之间的差异。
setTimeout(function(){
/* Some long block of code... */
setTimeout(arguments.callee, 10);
}, 10); setInterval(function(){
/* Some long block of code... */
}, 10);
两者的不同之处在于setTimeout在在10毫秒的delay之后执行代码(只会多余10毫秒,绝不会少),setInterval则在每隔10毫秒的延迟时执行回调代码,不管上次的回调是否已经执行完。
好了,本文中介绍的一些要点,现在回顾一下:
- JavaScript引擎在运行时只有一个线程,从而迫使异步事件排队等待执行。
- setTimeout和setInterval在执行异步代码的方式上不同。
- 如果定时器被阻止立即执行,它将延迟到下一个可能的执行点(比所需的延迟时间更长)。
- 如果定时器延迟的事件足够长,则在到点后会立即执行,没有延迟。
所有这些都是非常重要的基础知识。 了解JavaScript引擎的工作原理,尤其是在通常发生大量异步事件的情况下,为构建高级应用程序代码奠定了良好的基础。
来源:https://johnresig.com/blog/how-javascript-timers-work/
本文是John Resig很早的一篇文章,通过setTimeout,setInterval两个函数的比较,可以了解JavaScript事件循环机制。
JavaScript的定时器是如何工作的的更多相关文章
- JavaScript中定时器的暂停和继续
对于JavaScript的定时器来说没有严格意义上的暂停和重启,只有清除停止,但是可以通过一些‘障眼法’实现 allChild[index].onclick = function(){//当点击目标且 ...
- day27—JavaScript实现定时器及其应用案例
转行学开发,代码100天——2018-04-12 JavaScript中定时器有两种,分别是setInterval和setTimeout;其用法如下: 开启: setTimeout("fun ...
- Javascript中定时器的使用方法
Javascript中定时器的使用方法 1.间隔定时器(每隔一段时间执行一次代码) 格式:setInterval(函数,时间) //时间单位是毫秒,每隔设置的时间执行函数里的内容一遍(一直执行) // ...
- JavaScript中定时器
JavaScript提供定时执行代码的功能,叫做定时器(timer),主要由setTimeout()和setInterval()这两个函数来完成.它们向任务队列添加定时任务. setTimeout() ...
- 理解JavaScript的定时器与回调机制
定时器方法 JavaScript是单线程的.虽然HTML5已经开始支持异步js了. JavaScript的setTimeout与setInterval看起来就像已经是多线程的了.但实际上setTime ...
- Linux驱动技术(七) _内核定时器与延迟工作
内核定时器 软件上的定时器最终要依靠硬件时钟来实现,简单的说,内核会在时钟中断发生后检测各个注册到内核的定时器是否到期,如果到期,就回调相应的注册函数,将其作为中断底半部来执行.实际上,时钟中断处理程 ...
- JavaScript基础 -- 定时器
js 定时器有以下两个方法: setInterval() :按照指定的周期(以毫秒计)来调用函数或计算表达式.方法会不停地调用函数,直到 clearInterval() 被调用或窗口被关闭. set ...
- JavaScript 之 定时器
JavaScript 里面有两个定时器:setTimeout() 和 setInterval() . 区别: setTimeout():相当于一个定时炸弹,隔一段时间执行,并且只会执行一次就不在执行了 ...
- JavaScript clearInterval定时器失效原因
检查下是不是setInterval重复执行(两次以上<!-- 文件上传板块 --> <div id="adUploadWindow" class="ea ...
随机推荐
- zabbix导入数据库报错1046 (3D000) : No database selected
Zabbix导入数据库时报错 使用如下命令导入Zabbix数据库时报错 zcat /usr/share/doc/zabbix-server-mysql/create.sql.gz | mysql -u ...
- 【原创】go语言学习(二十一)Select和线程安全
目录 select语义介绍和使用 线程安全介绍 互斥锁介绍和实战 读写锁介绍和实战 原子操作介绍 select语义介绍和使用 1.多channel场景 A. 多个channel同时需要读取或写入,怎么 ...
- Codeforces 1109D: generalizations of Cayley's formula证明
做这题的时候发现题解里有提到\(generalizations\ of\ Cayley's\ formula\)的,当场懵逼,Wikipedia里也就带到了一下,没有解释怎么来的,然后下面贴了篇论文. ...
- 【控制系统数字仿真与CAD】实验一:状态方程、传函为模型的系统的仿真
一.实验目的 1. 掌握各数学模型之间的转换与数学模型的参数获取,掌握相关MATLAB命令 2. 掌握欧拉法和RK法的递推公式 3. 掌握欧拉法和RK法的MATLAB算法实现 二.实验内容 1. 分别 ...
- introduce new products
Today's the day. I'm giving you the heads up. Our company is rolling up its new line of cell phones. ...
- PHP判断数组下标有没有存在的方法
PHP判断数组下标有没有存在的方法<pre>if(!empty($token['errcode'])){ print_r($token['errmsg']); exit();}</p ...
- nsq (三) 消息传输的可靠性和持久化[二]diskqueue
上一篇主要说了一下nsq是如何保证消息被消费端成功消费,大概提了一下消息的持久化,--mem-queue-size 设置为 0,所有的消息将会存储到磁盘. 总有人说nsq的持久化问题,消除疑虑的方法就 ...
- python——多线程
多线程特点: • 线程的并发是利用cpu上下文的切换(是并发,不是并行) • 多线程执行的顺序是无序的 • 多线程共享全局变量 • 线程是继承在进程里的,没有进程就没有线程 • GIL全局解释器锁 • ...
- .NET Core3.0 EF 连接 MySql
一:创建项目 添加 csproj (或者直接NuGet 引用) <ItemGroup> <PackageReference Include="Microsoft.Entit ...
- Django 通过 ORM 实现表的CRUD
Django 通过 ORM 实现表的CRUD 单表的创建 修改 setting.py 文件 DATABASES = { 'default': { 'ENGINE': 'django.db.backen ...