[译]JavaScript中的Timer是怎么工作的
作者:罂粟 来源:译言 发布时间:2009-02-06 15:39:00
作为入门者来说,了解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之间的区别。
(function(){
/* 一个很长的代码块…… */
setTimeout(arguments.callee, 10);
}, 10);
setInterval(function(){
/* 一个很长的代码块…… */
}, 10);
乍看上去,这两段代码在功能上似乎是相同的,可实际上并非如此。setTimeout的代码在前一次的回调执行完后总是至少会有10ms的延时(有可能会更多,但是绝对不会更少);而setInterval则总是在每10ms的时候尝试执行一次回调,它不管上一次回调是什么时候执行的。
我们在此学到了很多,让我们重述一下:
JavaScript引擎只有一个线程,这使得异步事件必需列队等待执行。
setTimeout和
setInterval在如何执行代码上有着本质地区别。
如果一个timer在将要执行的时候被阻塞,它将会等待下一个时机(比预期的延时要长)。
如果interval的执行时间较长(比指定的延时长),那么它们将连续地执行而没有延时。
以上这些知识是相当重要的。知道JavaScript引擎的工作方式,尤其是知道它在有很多异步事件发生的时候是怎么工作的,为我们在写进阶的应用程序代码打下了坚实的基础。


猜你喜欢
- 操作方法:先要安装好SQLServer2005,并且记住安装时自己设置的用户名和密码。下面以恢复SQLServer下备份的数据库文件epdm
- 在 Facebook 上有一个彩蛋:登录 facebook.com ,点击你首页的任何地方,键盘输入 Up, Up, Down, Down,
- 优点:兼容性很好,而且俺觉得不应该有什么拦截工具可以拦截下来优点:代码非常短缺点:必须在页面点击后才会弹出demo:运行代码框<hea
- 项目演示:一、输入金额二、跳转到支付宝付款三、支付成功四、跳转回自己网站在使用支付宝接口的前期准备:1、支付宝公钥2、应用公钥3、应用私钥4
- 自个儿闲的发疯画几个老鼠的表情,送女朋友。。HOHO。经常欺负人。哎。其实被欺负是一种幸福。工作以美国时间为主,所以白天睡到晚上。我不傻,真
- 批量更新mysql更新语句很简单,更新一条数据的某个字段,一般这样写:UPDATE mytable SET myfield = 'v
- 一、Beautiful Soup的介绍Beautiful Soup是一个强大的解析工具,它借助网页结构和属性等特性来解析网页。它提供一些函数
- 通用视图1. 前言回想一下,在Django中view层起到的作用是相当于controller的角色,在view中实施的动作,一般是取得请求参
- 安装selenium打开命令控制符输入:pip install -U selenium火狐浏览器安装firebug:www.firebug.
- 不得不承认,傲游在用户体验方面是做得比较好的,所以它的用户群非常大。也正因为如此,它的某些不好的特性也造成了开发人员不可忽略的浏览器兼容问题
- python爬虫模块PyQuery简介PyQuery库也是一个非常强大又灵活的网页解析库,如果你有前端开发经验的,都应该接触过jQuery,
- 相关文章Pytest框架之fixture详解(一)Pytest框架之fixture详解(二)Pytest框架之fixture详解(三)本文关
- 数据平台 Kaggle 近日发布了 2017 机器学习及数据科学调查报告,这也是 Kaggle 首次进行全行业调查。调查共收到超过 1600
- 一、logging日志模块等级常见log级别从高到低:CRITICAL 》ERROR 》WARNING 》INFO 》DEBUG,默认等级为
- 大部分的pytorch入门教程,都是使用torchvision里面的数据进行训练和测试。如果我们是自己的图片数据,又该怎么做呢?一、我的数据
- 本文实例讲述了MySQL切分查询用法。分享给大家供大家参考,具体如下:对于大查询有时需要‘分而治之',将大查询切分为小查询: 每个查
- 一、基础介绍Go 是静态(编译型)语言,是区别于解释型语言的弱类型语言(静态:类型固定,强类型:不同类型不允许直接运算)例如 python
- def Num2MoneyFormat( change_number ): ""&q
- 编程语言中反射的概念在计算机科学领域,反射是指一类应用,它们能够自描述和自控制。也就是说,这类应用通过采用某种机制来实现对自己行为的描述(s
- 1.首先引入import { Toast } from 'vant'写个小列子绑定一个click事件2.写事件在method