JavaScript中的EventLoop(浏览器环境)

前言 

        最近在看JavaScript的EventLoop机制,理解这个机制,能够提高我们对JavaScript中异步处理和代码运行的认知和理解。

        查阅资料发现,JavaScript的eventloop机制在浏览器环境和nodejs环境是不同的,这篇文章是以浏览器环境为前提的。

        首先分区:

  • 控制台就是我们常用的测试输出的区域,这里用来显示测试输出。 
  • 代码段是我们将要执行的代码,并无区分,只是字符串。
  • 执行栈就是当前正在执行的代码区域,可以说这是JavaScript单线程的主线程执行,所有的执行结果会在这里产生。
  • WebApis是执行栈调用的各种Apis,比如DOM事件(点击,滑动,键盘等)、定时器事件(setTimeout,setInterval)、AJAX等,这些api可以在任务队列中添加各种事件
  • 任务队列是存放由WebApis置入的事件函数,等待Eventloop机制调用
  • EventLoop是一个轮询机制,当执行栈中的代码执行完毕之后,会取得任务队列队首的事件函数置入执行栈。

分析样例

        我们分析一个这一个段代码的执行过程,和几个分区的变换情况。

        1.首先,将目前的代码段置入执行栈

 

       2.执行第一行console.log('你好,我是杰哥');   执行结果就是在控制台打印字符串:你好,我是杰哥,并从执行栈删除这行代码。

 

        3.执行执行栈中 let set_timeout = setTimeout() 这段代码。这段代码将一个函数放到WebApis并在执行栈清空3s后将函数置入任务队列。

这里解释一下为什么我们把setTimeout()定时器函数调用结果赋值给一个变量。

首先要知道setTimeout是一个函数, 在函数后面加一个括号叫做函数调用表达式,就代表调这个函数。
而调用setTimeout这个函数的结果就是若干时间后执行代码。
你把setTimeut()赋值给另一个变量,只是把函数调用的结果(即返回值)给了那个量,定时器函数的返回值是一个整数。返回的是一个ID号。从1开始。
clearTimeout(set_timeout),会清除掉这个定时函数,但是不会改变id值。

在这里,set_timeout  =  1; set_interval  =  2;

         4.执行执行栈中 let set_timeout = setInterval() 这段代码。这段代码将一个函数放到WebApis中,并在执行栈清空后每一秒将此函数置入任务队列中一次。

 

         5.执行执行栈中的console.log('你好,我是灼子');执行结果就是在控制台打印字符串:你好,我是灼子,并从执行栈删除这行代码。

 

        6.至此,执行栈中的代码清空,然后EventLoop开始循环遍历任务队列中的事件函数,但是此时任务队列中并没有任务可执行。同时在执行栈中代码清空后,webApis开始运转(时间开始流转)在第1s后,setInterval定时器到时间,将函数function(){console.log('setInterval回调函数执行');}添加至任务队列。

 

 

   7.添加至任务队列之后,由于执行栈中并无执行代码,所以eventLoop一直在循环查看,发现任务队列中添加了新的任务函数后,立刻将此任务函数置入执行栈,并执行此代码(注意在执行过程中eventLoop是不会继续循环查看的,但是WebApis会继续读秒,因为无论是eventLoop还是执行栈中执行代码,速度都很快,所以WebApis的读秒不会明显的表现出来)。

   8.执行结束后删除执行栈中执行过的代码,删除后执行栈清空,此时EventLoop继续循环查看任务队列,WebApis仍然读秒,到2s的时候,setInterval定时器会再次将一个函数function(){console.log('setInterval回调函数执行');}添加至任务队列。

   9.由于执行栈为空,此时EventLoop一直在循环查看任务队列,在添加任务后,Eventloop会直接将任务队列中的代码置入执行栈,并执行,执行结束后清空执行栈。

 10.WebApis仍然在读秒,到第三秒时,setTimeout定时器和setInterval到时,这是会根据ID(即添加定时器先后顺序)执行将事件函数加入任务队列,setTimeout定时器先添加。添加后setTimeout定时器注销。EventLoop一直在循环查看任务队列

        注意,因为EventLoop一直在循环查看任务队列,当setTimeout定时器添加事件函数后,会立即置入执行栈并执行。这里我不确实是否会将setInterval定时器到时的事件函数置入任务队列,不过最后的结果是没有执行setInterval定时器的任务。我猜测是因为执行栈中的代码执行速度很快,注销setInterval定时器的时候,还未添加到任务队列。

  10.EventLoop一直在循环查看任务队列,当setTimeout定时器添加事件函数后,会立即置入执行栈并执行。按行执行代码,首先会执行console.log('setTimeout回调函数执行');并在控制台打印。然后会执行window.clearInterval(set_interval)会将webApis中的setInterval定时器取消,最后执行console.log("setInterval定时器注销");并在控制台打印。

 11.至此,执行栈、webApis、人任务队列都为空,代码执行完毕,分析的输出结果如下。我们在浏览器中测试一下。 执行结果如下,我们分析的结果与实际相符。

 总结

        本文是根据阮一峰笔记中的EventLoop相关内容,以及查阅一些文档总结分析的,如果有错误欢迎在评论区指正。

 

 

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值