EventLoop事件循环机制

176 阅读3分钟

什么是 EventLoop

JavaScript 的事件分两种,宏任务微任务

宏任务(macrotask,新标准中叫task): 包括整体代码 script(整体代码) 、 setTimeoutsetIntervalsetImediate

微任务(microtask,新标准中叫jobs)Promise.then(非 new Promise)、process.nextTick(node中)、MutationObserver(html5新特性)

事件的执行顺序 :先执行宏任务,然后执行微任务,任务有同步的任务和异步的任务,同步的任务进入主线程,异步的进入 Event Table并注册函数,异步事件完成后,会将回调函数放在队列中,如果还有异步的宏任务,那么就会进行事件循环执行上述的操作。

同步任务:在主线程上排队执行的任务,,只有前一个任务执行完毕,才能执行后一个任务

异步任务:不进入主线程,而进入任务队列(task quene)的任务,只有任务队列通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行

宏任务和微任务示例

// 1.宏任务 - 异步
setTimeout(() => {
    //执行后 回调一个宏事件
    console.log('1')
}, 0)

// 2.宏任务 - 同步
console.log('2');

// 3.宏任务 - 同步
new Promise((resolve) => {
    console.log('3');
    resolve()
}).then(() => {
    // 4.微任务 - 异步
    console.log('4');
}).then(() => {
    // 5.微任务 - 异步
    console.log('5')
})

// 2.宏任务 - 同步
console.log('6')

// print results : 2  3  6  4   5   1
async function async1() {
    // 1.宏任务-异步
    console.log("1")
    await async2();
    // 2.微任务-异步
    console.log("2")
}
// 3.宏任务-异步
async function async2() {
    console.log("3")
    // return promise对象
}
// 4.宏任务-同步
console.log("4")

// 5.宏任务-异步
setTimeout(function () {
    console.log("5")//最后执行
}, 0)

async1()

// 6.宏任务-同步
new Promise(function (resolve) {
    console.log("6")
    resolve()
}).then(function () {
    // 7.微任务-异步
    console.log("7")
})

// 8.宏任务-同步
console.log("8")
//print results:4 1 3 6 8 2 7 5

总结:事件循环先执行宏任务,其中同步任务立即执行,异步任务加载到对应的 Event quene 中,微任务也加载到对应的 Event quene 中,所有的同步微任务执行完之后,如果发现微任务的 Event quene 中有未执行完的任务,先执行他们。这样就算完成了一轮事件循环。接下来查看宏任务的队列中是否有异步代码,有的话执行第二轮的事件循环,以此类推。

setTimeout、Promise、async/await的区别

setTimeout 的回调函数放到宏任务队列里,属于宏任务中的异步任务,等到执行栈清空以后执行

Promise.then里的回调函数会放到相应宏任务的微任务队列里,等宏任务里面的同步代码执行完再执行

async 方法执行时,遇到 await 会立即执行表达式,然后把表达式后面的代码放到微任务队列里,让出执行栈让同步代码先执行

栈、堆、队列?(补充了解)

栈和堆的区别

  1. 栈区(stack):由编译器自动分配释放,存放函数的参数值,局部变量的值等。堆区(heap):一般由程序员分配释放,若程序员不释放,程序结束时可能由 OS 回收
  2. (数据结构):堆可以被看成是一颗树,如堆排序。(数据结构):一种先进后出的数据结构

栈和队列的区别

  1. 的插入和删除操作都是在一端进行的,而队列的操作确是在两端进行的
  2. 队列先进先出,先进后出
  3. 只允许在一端进行插入和删除,而队列允许在一端进行插入,在另一端进行删除