EventLoop简述

167 阅读2分钟

文章探讨一下两个个问题

什么是EventLoop?

解决什么问题?


js作为一门单线程网页脚本语言,诞生之初的作用便是操作dom。

由于是单线程语言,js一次只能执行一个任务,前面的任务执行完了才能执行下一个。这样一旦遇到大量任务或是遇到一个耗时的任务,网页就会出现假死,EventLoop正是为了解决这个问题。

托eventloop的福,js是非阻塞的。这是说当代码需要执行一项异步任务的时候,主线程会挂起这个任务,在异步任务返回结果的时候再根据一定规则去执行相应的回调。


重点1:事件队列(task queue)

js执行代码时,碰到异步事件,会将这个事件挂起,先执行其他任务。当一个异步事件返回结果后,js将其加入到与当前执行栈不同的另一个队列————事件队列。

重点2:何时执行

即便异步事件返回了结果,进入了事件队列,他也不会立即执行回调,而是等待当前执行栈中所有的任务执行完毕,主线程闲置才会去查看异步队列是否有任务,如果有,就取出这个队列第一位的事件,放入当前执行栈,开始执行其中的代码

重点3:如何执行

异步任务也是不相同的,分为宏任务(macro task)和(micro task)

  • 宏任务
    • setInterval()
    • setTimeout()
  • 微任务
    • new Promise()
    • new MutationObserver()

宏任务有宏任务的事件队列,微任务有微任务的事件队列,微任务优先执行,执行完毕才能执行下一个宏任务


总结


浏览器执行js代码时,先执行同步代码,中间碰到异步任务放到事件队列,如果是宏任务就放到宏任务队列,是微任务就放到微任务队列。同步代码执行完,当前执行栈为空,就去查看微任务队列,执行完毕后,取出第一位的宏任务执行。下一轮,继续同步事件——微任务——宏任务的执行方式。

async function async1() {
    console.log('async1 start');
    await async2();
    console.log('async1 end');
}
async function async2() {
    console.log('async2');
}
console.log('script start');
setTimeout(function() {
    console.log('setTimeout');
}, 0)
async1();
new Promise(function(resolve) {
    console.log('promise1');
    resolve();
}).then(function() {
    console.log('promise2');
});
console.log('script end');

/*
script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout
*/