• 微信号:wumiao_357234902
您当前的位置:首页>web前端开发>JavaScript

JavaScript事件执行机制

作者:Miao 阅读:3898次

因为javascript是一门单线程语言,所以我们可以得出结论:javascript是按照语句出现的顺序执行的。javascript每执行一个语句,我们称之为一次任务,因此可以将任务分为两类:同步任务和异步任务,先来看下面这张图:

1.jpg

  • 同步和异步任务分别进入不同的执行"场所",同步的进入主线程,异步的进入Event Table并注册函数。

  • 当指定的事情完成时,Event Table会将这个函数移入Event Queue(事件队列)。

  • 主线程内的任务执行完毕为空,会去读取Event Queue(事件队列)中对应的函数,进入主线程执行。

  • 上述过程会不断重复,也就是常说的Event Loop(事件循环)。


只看导图可能有些笼统,请结合下面这段代码:

console.log(1) // 同步
setTimeout(() => {
  console.log(2) // 异步,注册回调函数fn1
}, 2000);console.log(3) // 同步
setTimeout(() => {
  console.log(4) // 异步,注册回调函数fn2
}, 0);
console.log(5) // 同步
  • console.log(1)是一条同步任务,进入主线程;setTimeout(() => {console.log(2)}, 2000);是一条异步任务,进入Event Table,注册回调函数fn1;console.log(3)是一条同步任务,进入主线程;setTimeout(() => {console.log(4)}, 0);是一条异步任务,进入Event Table,注册回调函数fn2;console.log(5)是一条同步任务,进入主线程。

  • 由于setTimeout把回调函数fn2的延时设置为0,所以注册完回调函数后,Event Table会将立即将fn2移入Event Queue(事件队列);同理2s后Event Table将fn1移入Event Queue。这些操作进入队列的顺序,由设定的延迟时间来决定。

  • 所以主线程第一次执行完成后输出结果1、3、5,此时主线程内的任务为空,会去顺序读取Event Queue(事件队列)中的函数,所以主线程第二次执行完成后输出结果1、3、5、4。

  • 只要主线程的任务变为空,就回去Event Queue(事件队列)询问是否有可自行的回调函数,这时发现Event Queue(事件队列)中还有回调函数fn1,所以fn1会进入主线程执行,所以主线程第三次执行完成后输出结果1、3、5、4、2。

  • 到此,整个js事件执行结束。


前面说了,等所有同步代码都执行完,再从Event Queue(事件队列)里依次执行所有异步回调函数,实际上Event Queue(事件队列)也有自己的规则:Event Queue(事件队列)用来存异步回调,而异步任务分为宏任务和微任务,并且微任务执行时机先于宏任务

  • macro-task(宏任务):包括整体代码script,setTimeout,setInterval

  • micro-task(微任务):Promise,process.nextTick

整体代码是一个宏任务,进入整体代码(宏任务)后,开始第一次循环。接着执行所有的微任务。然后再次从宏任务开始,找到其中一个任务队列执行完毕,再执行所有的微任务,如下图所示:

2.jpg

setTimeout(function() {
    console.log('setTimeout');   // 异步:宏任务
})
new Promise(function(resolve) {
    console.log('promise');  // 同步
    resolve();
}).then(function() {
    console.log('then');   // 异步:微任务
})
console.log('console');   // 同步
  • 这段代码作为第一个宏任务,进入主线程,先遇到setTimeout,setTimeout异步执行,将其回调函数注册后分发到宏任务Event Queue。

  • 接下来遇到了Promise,new Promise立即执行,输出promise,then函数分发到微任务Event Queue。

  • 在往后遇到console.log(),立即执行,输出console。

  • 整体代码script作为第一个宏任务执行结束,输出结果promise console,Event Queue里面有微任务then在和宏任务setTimeout。

  • 执行微任务then,第一轮事件循环正式结束,这一轮的结果是输出promise console then。那么第二轮时间循环从setTimeout1宏任务开始。

  • 立即执行宏任务Event Queue中setTimeout对应的回调函数,回调函数中只有一个console.log(),执行完第二轮事件循环结束,输出promise console then setTimeout。


总结:

  • javascript是一门单线程语言

  • 事件轮询(Event Loop)是js实现异步的一种方法,也是js的执行机制

本站部分文章、数据、素材收集于网络,所有版权均归源网站或原作者所有!

如果侵犯了您的权益,请来信告知我们下线删除,邮箱:357234902@qq.com

标签:JavaScript