1

概述

最近看了一些异步的文章,有一些作者没有写代码也把错误的理解放上来。想想,我也应该总结一些,之前面试也有过一道题目,虽然说是考察异步,但其实就是考察异步当中的任务队列。给你一道题目,你觉得会依次输出什么?

console.log('1')

Promise.resolve().then(() => console.log('2'))

setTimeout(() => {console.log('3'); Promise.resolve().then(() => console.log('4'))}, 0)

Promise.resolve().then(() => console.log('5'))

setTimeout(() => console.log('6'), 0)

console.log('7')

答案是

1 7 2 5 3 4 6

如果你知道为什么会输出这些的话,那我想你不必看下面了,因为你也有大概的理解,如果没有的话,我就跟你分析一下吧。

先看一张图吧,是拿别人的,有部分原因也是因为他写的文章有错误,我才总结。

image

先理解这张图片吧,我简单介绍一下。

  • 栈:主线程的函数执行,异步操作的执行放在了异步处理模块。
  • 堆:用来存储引用类型的指向。
  • 异步处理模块:主线程里面的异步模块。
  • 任务队列:存储异步线程的执行队列。

然后,js运行就是运行主线程->运行任务队列

当然,这只是大概的介绍,真正的堆和栈并不是和他说的一样,栈里面还有内存栈和调用栈,内存栈又有全局的内存栈,也有某个函数的内存栈,当然,函数内部的内存栈又放在了堆里面。这里面的栈,仅仅是代表了调用栈。

宏任务队列(macrotasks)

什么是宏任务队列?

宏任务队列macrotasks: setTimeout, setInterval, setImmediate, I/O, UI rendering

上面的基本操作就是宏任务队列

微任务队列(microtasks)

微任务队列microtasks: process.nextTick, Promise, MutationObserver

上面的基本操作就是微任务队列

Event Loop

我就简单的说一下js里面执行顺序吧:

  1. 执行主线程,如果有异步操作,则放到异步队列执行。执行2
  2. 当主线程执行完毕,判断异步队列是否有微任务,如果有,则添加进去主线程执行;如果没有则将最新可以执行的宏任务加进主线程。返回1

是不是很简单?
那么上面那道题的结果无非就是

// 一开始,主线程
console.log('1');
console.log('7');

// 下一步,主线程
Promise.resolve().then(() => console.log('2'))

// 下一步,主线程
Promise.resolve().then(() => console.log('5'))

// 下一步,主线程
setTimeout(() => {console.log('3')}, 0)

// 下一步,主线程
Promise.resolve().then(() => console.log('4'))

// 下一步,主线程
setTimeout(() => console.log('6'), 0)

总结

看了一下很多文章,以为很难,很想画图,但是在写的过程中,发现其实真的很简单,只要好好了解js里面的引擎就好了,js还是一个很强大的单线程语言。


广工小成
1.3k 声望2.9k 粉丝