有些问题的答案如果您觉得不够严谨,欢迎评论区指正,多谢🙏
1、为什么调用堆栈,用栈不用队列呢?
你写代码肯定有缩进吧?每缩进一次,代表着代码更深了一层,这种层层深入的代码必然要用栈来运行。如果这样说不好理解,你可以找一个解析入栈出栈的例子,看一下就理解了
2、调用堆栈,栈我懂,堆是干嘛的?
首先必须说栈这种存储结构只能存基本类型,像数组和对象这种引用类型都是存在堆中的。说到这如果你焕然大悟了,那么你就可以直接看下一个问题了。
干了几年前端的你可能对堆有点陌生,不妨回忆一下你大学时候学的二叉树和先序遍历、中序遍历、后序遍历,那不就是讲的堆的存储嘛,想起来了吧
现在明白堆是干嘛的了吧,没有堆数据都没办法处理
3、调用堆栈我懂了,执行栈又是什么鬼?
有的介绍事件循环的文章中提到过执行栈,你可能也听过这个词。实际上这个词是不准确的,它应该叫做执行上下文
4、执行上下文是什么?
上下文的概念有点作用域的感觉。上下文分为全局上下文、函数上下文。全局上下文就是script全局代码,也是第一个进入调用堆栈的宏任务,它的进入标志着第一轮循环的开始。而函数上下文,比如一个promise,一个普通函数都叫函数上下文。
在调用堆栈中,入栈时是一个上下文一个上下文的入,并且入一个执行一个,执行完出栈。
5、都说Javascript是单线程的,但我听说还有GUI渲染线程、定时器触发线程等等,这不是多线程吗?
说Javascript是单线程,是说它代码跑起来的这个进程是单线程的。浏览器虽然还提供了个GUI渲染线程,但是它和JS线程是互斥的。
而且浏览器提供的不止有GUI渲染线程,还有用来给定时器计时的线程、网络请求线程、判断回调能否执行的线程。这些浏览器线程统称为浏览器异步模块,是用来辅助JS主线程的
6、我知道任务队列按种类分可以分为宏任务队列、微任务队列,但是到底有几个任务队列呢?
任务队列是按照任务源区分的,可能有无数个,这里我来分析一下,说的不对欢迎指正。
在宏任务队列(消息队列)中,setTimeOut和setInterval属于相同的任务源,属于同一任务队列。用户触发事件和onLoad这样的DOM事件属于同一任务队列。网络请求Ajax属于一个任务队列。上下文算宏任务,应该也有一个任务队列
在微任务队列(作业队列)中,主要就是promise和回调函数(包括await之后语句)任务队列
7、完整的事件循环过程是怎么样的?
一开始,调用堆栈要先执行当前排在宏任务队列中第一位的宏任务,也就是script全局代码(又叫全局上下文)。然后执行中遇到的一些代码该放入宏任务队列放入宏任务队列,该放入微任务队列放入微任务队列。之后检查微任务队列并且执行所有的微任务。
所有微任务执行完了再找到一个当前在宏任务队列中排第一位的宏任务开始执行,循环开始了
8、为什么宏任务是一次执行一个,微任务是一次执行一队?
宏任务一个一个执行本身就是事件循环的基本规则之一。一个宏任务执行完,检测微任务队列并且执行整队的微任务,然后再轮训执行宏任务队列中排在第一的宏任务。这是规则。
微任务我们只看promise。promise是用来实现同步的,这就使得它无法存在于正常的宏任务所参与的事件循环之中。而微任务队列不清空就无法执行别的任务的这种模式,你会发现它是有阻塞的,本质上就是为了实现同步。
9、为什么微任务要比宏任务优先?
应该说在一个宏任务中(这里的宏任务指上下文),微任务队列的清空,比其中的宏任务执行优先。这是因为微任务队列中的任务是同步的,而宏任务是异步的,当然微任务队列优先处理