事件队列(EventLoop)【宏任务,微任务】

发布时间 2023-06-13 14:39:50作者: 有只小菜猫

一、概念

event:事件

loop:循环,循环的是一个又一个的任务队列

任务队列:是一个先进先出的数据结构,排在前面的事件,优先被主线程读取

任务队列分为:宏队列,微队列,分别存放宏任务和微任务

二、宏任务【多个】、微任务【1个】

微任务一般比宏任务先执行,并且微任务队列只有一个,宏任务队列可能有多个

我们常见的点击和键盘等事件也属于宏任务

1、常见宏任务

  • setTimeout()
  • setInterval()
  • setImmediate()
  • script全部代码

2、常见微任务

  • promise.then()
  • promise.catch()
  • new MutaionObserver()
  • process.nextTick()

3、本质区别

(1)宏任务特征:有明确的异步任务需要执行和回调;需要其他异步线程支持。

(2)微任务特征:没有明确的异步任务需要执行,只有回调;不需要其他异步线程支持。

4、执行顺序【这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop(事件循环)】

console.log  =  promise  >  promise.nextTick  >  promise.then  >  setTimeout  >  setImmediate

(1)先按代码顺序将同步任务压入主执行栈中执行

(2)遇到异步任务则先将异步任务压入对应的任务队列中(宏队列或微队列)

(3)同步任务执行完毕后,查看微队列,将微任务一一取出进入主执行栈中执行

(4)微任务队列清空后,再查看宏队列,只取出第一个宏任务执行,执行完一个宏任务后,回到第三步的操作

          

【then中的回调函数要确定Promise状态后才能压入微队列】

// Promise中的执行顺序
 
let promise = new Promise(function(resolve, reject) {
    console.log('Promise');
    resolve();
});
 
promise.then(function() {
    console.log('resolved');
});
 
console.log('Hi!');//Promise//Hi! //resolved
//执行顺序
setTimeout(function () { console.log(1); }); new Promise(function(resolve,reject){ console.log(2) resolve(3); }).then(function(val){ console.log(val); new Promise((resolve, reject) => { console.log(5) resolve(7) }).then(res => { console.log(res); }) }) console.log(4); //先按顺序执行同步任务, //Promise新建后立即执行输出2,接着输出4,异步任务等同步任务执行完后执行, //且同一次事件循环中,微任务永远在宏任务之前执行。这时候执行栈空了,执行事件队列, // 先取出微任务,输出3,最后取出一个宏任务,输出1。

练习:

console.log('1主线程');                    //整体script作为第一个宏任务进入主线程
setTimeout(function() {                //setTimeout,其回调函数被分发到宏任务Event Queue(执行规则:从上到下排序,先进先执行)中
    console.log('2宏任务');
    process.nextTick(function() {
        console.log('3宏任务里面的微任务');
    })
    new Promise(function(resolve) {
        console.log('4微任务');
        resolve();
    }).then(function() {
        console.log('5微任务')
    })
})
process.nextTick(function() {    //process.nextTick()其回调函数被分发到微任务Event Queue中
    console.log('6微任务');
})
new Promise(function(resolve) {        //Promise,new Promise直接执行,输出7
    console.log('7微任务');
    resolve();
}).then(function() {
    console.log('8微任务')            //then被分发到微任务Event Queue中,排在process.nextTick微任务后面。
})
setTimeout(function() {            //setTimeout,其回调函数被分发到宏任务Event Queue中,排在前面的setTimeout后面
    console.log('9宏任务');
    process.nextTick(function() {
        console.log('10宏任务里面的微任务');
    })
    new Promise(function(resolve) {
        console.log('11微任务');
        resolve();
    }).then(function() {
        console.log('12微任务')
    })
})
 
//执行结果: 1主线程、7微任务、6微任务、8微任务、2宏任务、4微任务、3宏任务里面的微任务、5微任务、
//          9宏任务、11微任务、10宏任务里面的微任务、12微任务
// 先执行微任务、再执行宏任务