资讯专栏INFORMATION COLUMN

setTimeout的理解

huashiou / 2328人阅读

摘要:是的,没错是单线程的,但是会另开一个线程,这个线程依赖于某个计时装置,这时,其实是不管而继续往下进行的,而也是独立的线程计时的。

setTimeout的运行机制

先看下面一个例子:

这个代码会让浏览器陷入崩溃,为什么?
其实:
当javascript运行时遇到setTimeout后其实会另开一条线程(刚刚不是说javascript是单线程的嘛?)。是的,没错javascript是单线程的,但是setTimeout会另开一个线程,这个线程依赖于某个计时装置,这时,javascript其实是不管setTimeout而继续往下进行的,而setTimeout也是独立的线程计时的。而javascript在运行完全部的代码后会回过头来重新检测自己的队列中有没待执行的命令或者函数,如果有就执行,没有就等待。直到有待执行的命令被加载进这个队列中然后执行。在这期间,setTimeout依赖的那个计时线程如果时间到了,那么它会把setTimeout中要执行的函数或者命令传送到javascript的等待队列中,等待javascript执行完命令后回头来检测等待队列中未执行的函数或命令。
所以,在这里案例中,首先t变成true,然后javascript往下执行,遇到了setTimeout,这时setTimeout启用了另一个计时线程。此时javascript不管它跳过(因为它由另一个线程来控制)。然后遇到了while(t)这个循环,因为前面把t设置成了真,所以这个循环一直成立,所以也就一直循环下去。javascript的线程一直结束不了,所以无法回来检查等待队列,根本不会执行setTimeout中代码。所以t永远也无法变成假,而javascript也永远无法停止。

setTimeout的执行顺序

了解了setTimeout的运行机制后 我们来看看几个setTimeout并列运行 它们的执行顺序由什么决定

setTimeout(function(){
console.log(3);
},5000);
setTimeout(function(){
console.log(5);
},3000);
setTimeout(function(){
console.log(6);
},14000);

结果是5,3,6。几个都是setTimeout,因此都会放到等待队列~~~
而这些队列里的函数谁先执行呢?就是根据setTimeout里的第二个参数(延迟时间)决定的。
再看看一个复杂的例子 如果setTimeout中嵌套了setTimeout 呢?

var d=[];
d[0]=function(){setTimeout(function(){console.log(3);setTimeout(function(){console.log(4)})})};
d[1]=function(){setTimeout(function(){console.log(5);setTimeout(function(){console.log(6)},0)},100)};
for(var i=0;i<2;i++){d[i]();}

这段代码 按顺序打印的是 3,4,5,6 实际上是这样 主程序执行完后 遇到了两个settimeout函数 第一个是0毫秒,第二是100毫秒 先执行第一个settimeout,打印出3,
第一个函数执行的时候又遇见了一个settimeout 加入队列 等待时间是0,打印出了4,登到了100毫秒后 第二个settimeout被执行 打印出5.又遇见一个settimeout,同样被加入队列 等了0毫秒 被执行
再换换数据试一试:

var d=[];d[0]=function(){setTimeout(function(){console.log(3);setTimeout(function(){console.log(4)})})};
d[1]=function(){setTimeout(function(){console.log(5);setTimeout(function(){console.log(6)})},2)};
for(var i=0;i<2;i++){d[i]();}

这里的时间相差极短 打印出的顺序是3,5,4,6
如果再换一下数据:

var d=[];d[0]=function(){setTimeout(function(){console.log(3);setTimeout(function(){console.log(4)})})};
d[1]=function(){setTimeout(function(){console.log(5);setTimeout(function(){console.log(6)})},4)};
for(var i=0;i<2;i++){d[i]();}

这里相比上面的案例只是改了一个数字 2毫秒改成了4毫秒 执行顺序变成 3,4,5,6
为什么?
因为上面的案例执行完第一个settimeout之后 过了2毫秒了 超过了第二个函数的等待时间 会立即执行第二个settimeout。如果等待时间过大 就不会这样了
总之,只需记住一点:延迟时间始终是相对主程序执行完毕的那个时间算的 ,并且多个setTimeout的先后顺序也是由这个延迟时间决定的,如果遇到某个setTimeout需要花费大量的时间怎么办?可由于js是单线程,所以当执行到这个setTimeout后,会将这个程序执行完成后再去执行下一个setTimeout,无论下一个setTimeout的延迟时间为多少,如果这两个setTimeout时间的差值小于第一个setTimeout消耗的时间,程序会等待这个setTimeout执行完成后立即执行下一个setTimeout,如果差值大于消耗的时间,就按照和主程序约定的延迟(setTimeout里的第二个参数)执行即可

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

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

相关文章

  • javascript引擎执行过程理解--执行阶段

    摘要:如果对语法分析和预编译,还有疑问引擎执行的过程的理解语法分析和预编译阶段。参与执行过程的线程分别是引擎线程也称为内核,负责解析执行脚本程序的主线程例如引擎。以上便是引擎执行宏任务的整个过程。 一、概述 js引擎执行过程主要分为三个阶段,分别是语法分析,预编译和执行阶段,上篇文章我们介绍了语法分析和预编译阶段,那么我们先做个简单概括,如下: 1、语法分析: 分别对加载完成的代码块进行语法...

    SnaiLiu 评论0 收藏0
  • javascript引擎执行过程理解--执行阶段

    摘要:如果对语法分析和预编译,还有疑问引擎执行的过程的理解语法分析和预编译阶段。参与执行过程的线程分别是引擎线程也称为内核,负责解析执行脚本程序的主线程例如引擎。以上便是引擎执行宏任务的整个过程。一、概述 js引擎执行过程主要分为三个阶段,分别是语法分析,预编译和执行阶段,上篇文章我们介绍了语法分析和预编译阶段,那么我们先做个简单概括,如下: 1、语法分析: 分别对加载完成的代码块进行语法检验,语...

    Achilles 评论0 收藏0
  • JavaScript执行机制、事件循环

    摘要:曾经的理解首先,是单线程语言,也就意味着同一个时间只能做一件事,那么为什么不是多线程呢这样还能提高效率啊假定同时有两个线程,一个线程在某个节点上编辑了内容,而另一个线程删除了这个节点,这时浏览器就很懵逼了,到底以执行哪个操作呢所以,设计者把 Event Loop曾经的理解 首先,JS是单线程语言,也就意味着同一个时间只能做一件事,那么 为什么JavaScript不是多线程呢?这样还能提...

    rose 评论0 收藏0
  • setTimeout和setInterval

    摘要:一个页面在浏览器显示出来至少需要个线程,分别是引擎,渲染,事件触发。其中事件触发是独立于其他个执行的,而和是相互排斥的,也就是说同一个时间二者只有一个在工作。 作为DOM本身十分重要的2个异步执行函数,初学者感觉这个很不好理解,我简单写一写我的理解 setTimeout (func, millisec); setInterval(func, millisec); 这两个方法在形式看起来...

    SnaiLiu 评论0 收藏0
  • JavaScriptsetTimeout和setInterval深入理解

    摘要:所以其实和所谓的异步调用事实上是通过将代码段插入到代码的执行队列中实现的。当执行和的时候,会根据你设定的时间准确地找到代码的插入点。综上所述,其实终归是单线程产物。无论如何异步都不可能突破单线程这个障碍。 发表过一片博客《跟着我用JavaScript写计时器》,比较基础.....有网友说应该写一下setTimeout的原理和机制,嗯,今天就来写一下吧: 直奔主题:setTimeout和...

    cgh1999520 评论0 收藏0

发表评论

0条评论

huashiou

|高级讲师

TA的文章

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