资讯专栏INFORMATION COLUMN

谈谈我对js中定时器的一点理解

frontoldman / 1733人阅读

摘要:这两个函数接受定时器的例如我们上面提到的两个函数产生的定时器,并停止对定时器中指定函数的调用。注意,定时器虽然触发了,但是并不会立即执行,它只是把需要延迟执行的函数加入了执行队列,在线程的某一个可用的时间点,这个函数就能够得到执行。

撸了今年阿里、头条和美团的面试,我有一个重要发现.......

javascript定时器工作原理是一个重要的基础知识点。因为定时器在单线程中工作,它们表现出的行为很直观。我们该如何创建和维护定时器呢?要从如下三个函数(都是定义在全局作用域,在浏览器中就是window的方法)说起:

var id=setTimeout(fn,delay);
-初始化一个只执行一次的定时器,这个定时器会在指定的时间延迟delay之后调用函数fn,该setTimeout函数返回定时器的唯一id,我们可以通过这个id来取消定时器的执行。

var id=setInvertal(fn,delay);
-与setTimeout类似,只是它会以delay为周期,反复调用函数fn,直到我们通过id取消该定时器。

clearInterval(id);clearTimeout(id);

-这两个函数接受定时器的id(例如我们上面提到的两个函数产生的定时器id),并停止对定时器中指定函数的调用。

要深入理解定时器工作原理,我们需要探索一个重要的概念:定时器指定的延迟时间并不能得到保证。在浏览器中,因为所有的javascript代码都运行在单一线程之中,异步事件(如鼠标点击,定时器)只有在他们被触发的时候他们的回调才有机会得以执行。我们可以用下图说明:

图中包含大量的信息,吸收并理解这些信息,能帮助我们领悟“异步的javascript代码是如何工作的”。这个图是一维的,垂直方向是时间,以毫秒为单位。蓝色的盒子代表正在执行的javascript代码所占时间片段。例如 第一个javascript块执行时间约18ms,第二个鼠标点击块执行了约11ms,其他块类似。

因为单线程的缘故,在同一时间只能执行一条javascript代码,每一个代码块(蓝色盒子)都会阻塞其他异步事件的执行。这就意味着,当一个异步事件发生的时候(例如鼠标点击,定时器触发,一个XMLHttpRequest 请求完成),它进入了代码的执行队列,执行线程空闲时会依照该执行队列中顺序依次执行代码。(如何将异步事件加入队列,不同浏览器,他们的实现可能有所差异,所以这里我们将其简单化)。

开始的时候,在Javascript代码块(第一个盒子),初始化了两个定时器,一个10ms延迟的setTimeout 和10ms的setInterval。这些定时器可能会在我们第一个代码块执行结束之前就触发,这取决于定时器在第一个代码块中启动的位置和时间。注意,定时器虽然触发了,但是并不会立即执行,它只是把需要延迟执行的函数加入了执行队列,在线程的某一个可用的时间点,这个函数就能够得到执行。

当第一个Javascript代码初始化块执行结束,浏览器立即提出一个问题:谁在等待着被执行? 在这个案例中鼠标点击时间的处理程序和一个定时器(setTimeout)都在等待。浏览器选择一个并执行(这里是鼠标点击事件的处理程序)。定时器就需要等待下一个可用时间来执行。

需要注意的是当鼠标点击事件处理程序执行的时候,第一个interval定时器触发了。和timeout定时器一样,他的回调函数被加入了执行队列,等待执行。然而,还需要注意到当interval定时器再次触发,这个时候timeout定时器的回调函数正在执行,此时这个interval的触发被放弃了。假想(浏览器不这样做),在一个占用时间很多的初始化定时器的代码块中,所有的interval触发都把回调加入执行队列,当初始化代码块结束后,执行队列中已经累加了大量的定时器回调函数,结果就会出现大量的interval回调函数无间隔的执行,直到该执行队列清空。所以浏览器在讲一个interval回调加入执行队列前,会检查执行队列,如果其中存在尚未执行的interval回调那么就等待,直到当前执行队列中没有相应interval的回调以后才会继续入队interval回调。

事实上,如图,我们看见在第一个Interval的回调执行的时候(之前进入执行队列),第三个interval触发了,这想我们展示一个重要的现象:Interval不关心当前正在执行的代码,他们会不加选择的添加回调到执行队列,尽管这意味着两个interval回调函数执行的时间间隔被牺牲。这里第一个interval回调执行结束后,紧跟着第三个interval的回调马上得到执行,中间没有印象中应该有的10ms间隔。

最终,在第三个interval的回调执行结束后,我们看见执行队列中没有等待javascript引擎执行的代码,这就意味着,浏览器现在等待新的异步事件的发生,在50ms的刻度处interval再次触发,此时没有什么会阻塞javascript引擎,这个interval回调会立即执行。

让我们看一个例子来阐明,setInterval和setTimeout的不同,

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

看第一眼,会觉得这两段代码功能相同,实际上,他们是不同的。

   需要注意到,setTimeout的回调函数的执行总是保证了至少10ms的间隔(与上一个回调的执行相比,实际执行时,这个间隔可能变长,但是不可能更少),但是setInterval会尝试每隔10ms执行一次回调,不管上一个回调函数时候已经执行完毕。(很多类库的动画都是使用的setTimeout实现)

这里我们学到很多,总结一下:

javascript引擎是单线程的,会迫使异步事件进入执行队列,等待执行。

setTimeout和setInterval在执行异步代码时从根本上是有所不同的。

如果一个定时器事件被阻塞,使得它不能立即执行,那么它会被延迟,直到下一个可能的时间点,才被执行(这可能比你指定的delay时间要长)

Interval的回调有可能‘背靠背’无间隔的执行,这种情况是说interval的回调函数的执行时间比你指定的delay时间还要长

  这些都是构建javascript应用程序非常重要的知识。了解javascript Engine是如何工作的,特别存在大量的异步事件发生,为构建高级应用程序代码打下基础。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/106489.html

相关文章

  • 10分钟理解JS引擎的执行机制

    摘要:深入理解引擎的执行机制灵魂三问为什么是单线程的为什么需要异步单线程又是如何实现异步的呢中的中的说说首先请牢记点是单线程语言的是的执行机制。 深入理解JS引擎的执行机制 1.灵魂三问 : JS为什么是单线程的? 为什么需要异步? 单线程又是如何实现异步的呢? 2.JS中的event loop(1) 3.JS中的event loop(2) 4.说说setTimeout 首先,请牢记2...

    zzbo 评论0 收藏0
  • 谈谈我对面向对象以及类与对象的理解

    showImg(https://segmentfault.com/img/remote/1460000007103938?w=391&h=247); 文章最初发表于我的个人博客非典型性程序猿 对于刚接触JAVA或者其他面向对象编程语言的朋友们来说,可能一开始都很难理解面向对象的概念以及类和对象的关系。笔者曾经带过一个短期培训班教授java入门基础,在最后结束课程的时候,还有很多同学不太理解面向对象...

    walterrwu 评论0 收藏0
  • 深入理解js引擎的执行机制

    摘要:深入理解引擎的执行机制最近在反省,很多知识都是只会用,不理解底层的知识。在阅读之前,请先记住两点是单线程语言的是的执行机制。所以,是存在异步执行的,比如单线程是怎么实现异步的场景描述通过事件循环,所以说,理解了机制,也就理解了的执行机制啦。 深入理解js引擎的执行机制 最近在反省,很多知识都是只会用,不理解底层的知识。所以在开发过程中遇到一些奇怪的比较难解决的bug,在思考的时候就会收...

    feng409 评论0 收藏0
  • 谈谈 javascript 面向对象的一些细节问题

    摘要:同时,创建的子类有几个固定字段,分别是初始化函数原型初始化函数对象通过这个函数,把基类和子类的函数合并执行,这样解决了基类构造函数无法执行的问题。二是构造函数可能不止会操作,还可能会修改全局的某些状态比如计数器。 综述 在 ES6 之前,ES5 实现面向对象是大家经常讨论的问题,趁着 ES6 还没进入浏览器,借我自己的一段脚本,跟大家讨论一下 js 面向对象的一些细节问题,欢迎留言指教...

    newsning 评论0 收藏0
  • 计算机常识 - 收藏集 - 掘金

    摘要:使用简记后端掘金全称为即消息队列。优测优社区干货精选老司机乱谈编辑器之神掘金前言是一种信仰,我自从年有了这个信仰,已经个年头了。 PHP 程序员进阶学习书籍参考指南 - 后端 - 掘金PHP程序员进阶学习书籍参考指南 @heiyeluren lastmodify: 2016/2/18 ... 当我们在谈论前端加密时,我们在谈些什么 - 前端 - 掘金潘建旭,岂安科技(www.bigse...

    Yi_Zhi_Yu 评论0 收藏0

发表评论

0条评论

frontoldman

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<