以题理解经典面试题——三六九等的事件环

引言:## 因为最近在准备前端面试,作为很重要的事件环当然不得不回顾一下了,但是大牛们解释的实在是(字好多)根本看不进去,所以我觉得直接用题目理解。

在理解事件环之前,我们首先需要快速理解什么是堆和栈
维基百科:在javaScript中,栈中存的是基本数据类型,会自动分配内存空间,自动释放;堆中存的是引用数据类型,是动态分配的内存,大小不定也不会自动释放。
heap堆:也可以叫堆内存;是一种队列优先,先进先出的数据结构;
stack栈:又名’堆栈’,也是一种数据结构,不过它是按照先进后出原则存储数据的。

这一块想理解可以搜其他厉害的大牛,我只是走个流程(嘻嘻

下面我们进入主题:

宏任务和微任务

宏任务和微任务可以说都是异步任务。如果了解vue源码的同学,应该知道宏任务macrotask和微任务microtask这两个概念,他们的执行时机是不一样的。vue的$nextTick的源码就是通过宏任务和微任务实现的。

常见的宏任务macrotask有:setTimeout、setInterval、 setImmediate(ie浏览器才支持,node中自己也实现了)、MessageChannel
常见的微任务microtask有:promise.then()、process.nextTick(node的)

setTimeout(() => {
    console.log('setTimeout1');
},1000);
Promise.resolve().then(data => {
    console.log('then1');
});
console.log(2);

建议直接复制进入调试器输出,我们看到的答案就是 2 then1 setTimeout1

好的,我们现在来看看他的执行顺序
浏览器会从上到下执行代码,他会先找同步任务也就是console.log(2)当同步任务结束完了就开始寻找微任务进行执行也就是 promise.then 等扫完了栈内所有的微任务之后进行最后的宏任务。

执行顺序就是: 同步——微任务——宏任务

理解这个之后,在复制下面的代码执行

setTimeout(() => {
    console.log('setTimeout1');
    Promise.resolve().then(data => {
        console.log('then3');
    });
},1000);
Promise.resolve().then(data => {
    console.log('then1');
});
Promise.resolve().then(data => {
    console.log('then2');
    setTimeout(() => {
        console.log('setTimeout2');
    },1000);
});
console.log(2);

我们可以看到 2 then1 then2 setTimeout1 then3 setTimeout2

总结一下:
先执行栈中的内容,也就是同步代码,所以2被输出出来;
然后清空微任务,所以依次输出的是 then1 then2;
因代码是从上到下执行的,所以1s后 setTimeout1 被执行输出;
接着再次清空微任务,then3被输出;
最后执行输出setTimeout2

那么我们增加一下难度

setTimeout(() => {
    console.log('setTimeout1');
     setTimeout(() => {
        console.log('setTimeout3');
    },1000);
    Promise.resolve().then(data => {
        console.log('then3');
    });
},1000);
Promise.resolve().then(data => {
    console.log('then1');
    console.log('then4')
    Promise.resolve().then(data11=>{console.log('then6')})
});
Promise.resolve().then(data => {
    console.log('then2');
    console.log('then5')
    setTimeout(() => {
        console.log('setTimeout2');
    },1000);
});
console.log(2);

答案是 2 then1 then4 then2 then5 then6 setTimeout1 then3 setTimeout2 setTimeout3

那我们来排列一下顺序
1.setTimeout宏任务放第一个,两个primise微任务出现了,执行顺序变成了 promise-promise-setTimeout,然后又来了同步任务console.log(),最后就是console.log-promise-promise-setTimeout
2.执行完console之后,进入微任务,进入第一个promise,也是先排顺序就是两个console先执行,然后是一个微任务promise放着不管,看看第二个promise里面也有两个同步任务console和一个宏任务setTimeout2(放着不管)
顺序就是 第一个promise的同步任务 两个console - 第二个同步任务的两个console 这时候看看外面等着的是个 setTimeout宏任务,所以不管,继续看微任务里面有个 promise 所以执行 打印出then6,此时我们的同步任务和微任务已经执行完了,可以执行早早等着的宏任务了
3.这时候回到早早就等着的setTimeout虽然他第一个来,但是谁叫他地位低呢,然后开始执行也是 同步——微任务——宏任务
所以很简单打印出来是 setTimeout1-then3 因为这时又只剩下宏任务了,所以要去全局看看有没有等着的宏任务,也就是 第二个 promise内的setTimeout2,谁叫他是微任务内的宏任务呢,就是比宏任务内的宏任务地位高(怎么感觉像绕口令)

总结一下

同步任务最大然后是微任务最后是宏任务,值得一提的是微任务内的所有宏任务地位都比宏任务内的宏任务地位大。

我这里只是粗粗写了点理解,对于其他的宏、微任务也同样适用,如果要考虑到node的事件环道理也是一样的,可以找找大牛的博客理解一下。

如果大家还是不怎么理解,还是多打印几道题,自行理解吧~好了我继续复习了,大家有钱再见。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值