1. 事件循环Event Loop 概念介绍
事件循环Event Loop又叫事件队列,两者是一个概念.
官方定义: 事件循环指的是js代码所在运行环境(浏览器、nodejs)编译器的一种解析执行规则。
在js中讨论事件循环是没有意义的,
: 事件循环不属于js代码本身的范畴,而是属于js编译器的范畴
通俗的来说, js代码可以理解为是一个人在公司中具体做的事情, 而 事件循环 相当于是公司的一种规章制度。 两者不是一个层面的概念。
2. 事件循环Event Loop 执行机制
说到事件循环,就必须先了解JS代码的分类和执行机制
2.1 JS代码的分类
同步任务:同步任务不需要进行等待,必须立即看到执行结果,比如console,alert
异步任务:异步任务需要等待一定的时候才能看到结果,比如setTimeout、网络请求
下面是常用的宏任务和微任务代码:
注意:
new Promise函数体里面的代码是同步代码,只有promise.then()的then括号里面的代码是微任务代码
new Promise((resolve, reject) => {console.log(8); //同步代码resolve();console.log(9) //同步代码}).then(res => {console.log(10);//微任务代码})
async/await 右边的代码是同步代码, async/await下面的才是微任务代码
async function fnOne() { console.log(2); //同步任务 await fnTwo(); // 同步任务 console.log(3); //异步微任务 } async function fnTwo() { console.log(4); } fnOne();
2.2 JS事件循环执行机制
1.进入到script标签,就进入到了第一次事件循环.
2.遇到同步代码,立即执行
3.遇到宏任务,放入到宏任务队列里.
4.遇到微任务,放入到微任务队列里.
5.执行完所有同步代码
6.执行微任务代码
7.微任务代码执行完毕,本次队列清空
寻找下一个宏任务,重复步骤1
以此反复直到清空所以宏任务,这种不断重复的执行机制,就叫做事件循环
了解了js代码的分类和js事件循环的机制之后, 不管多复杂的面试题都能轻轻松松的拿下了.
3. 面试题
3.1 先来个简单的
<script> console.log(1) //同步代码 setTimeout(function () { console.log(2) new Promise(function (resolve) { console.log(3) resolve() }).then(function () { console.log(4) }) }) new Promise(function (resolve) { console.log(5) resolve() }).then(function () { console.log(6) }) setTimeout(function () { console.log(7) new Promise(function (resolve) { console.log(8) resolve() }).then(function () { console.log(9) }) }) console.log(10) </script>
思路分析: 1, 先按照代码类别执行同步代码
2, 同步代码执行完毕之后,再去执行微任务里面的代码,此时已执行完的代码顺序是这样的:
3, 微任务的代码执行完毕之后,先执行宏任务里面的第一块代码
4, 再去执行宏任务里面的第二块代码
最后,代码的执行顺序如下:
3.2 再来个难一点的
<script> console.log(1); async function fnOne() { console.log(2); await fnTwo(); // 右边先执行右侧的代码, 然后等待 console.log(3); } async function fnTwo() { console.log(4);// } fnOne(); setTimeout(() => { console.log(5); }, 2000); let p = new Promise((resolve, reject) => { // new Promise()里的函数体会马上执行所有代码 console.log(6); resolve(); console.log(7); }) setTimeout(() => { console.log(8) }, 0) p.then(() => { console.log(9); }) console.log(10); </script> <script> console.log(11); setTimeout(() => { console.log(12); let p = new Promise((resolve) => { resolve(13); }) p.then(res => { console.log(res); }) console.log(15); }, 0) console.log(14); </script>
思路分析: 1, 先判断每个代码是同步还是异步,先执行同步代码
2, 同步代码执行完毕之后再去微任务里面执行微任务代码
3, 微任务代码执行完毕后,再去执行宏任务里面的代码
注意点: (1)如果页面有多个script标签,多余的script标签可以理解为是一个独立的事件循环, 并且script标签是一个特殊的宏任务,优先级比定时器更高执行
所以此处宏任务队列里面优先执行script标签里面的代码,然后再执行定时器里面的代码
另外微任务的script标签里面既有同步代码,又有异步代码,又需要进行第二轮的代码分类
接下来,再去执行宏任务里面三个定时器里面的代码
以此类推,最后代码的执行顺序就是这样子滴
总之一句话,只要搞懂了事件循环机制和js代码分类,再复杂的面试题都能so easy的解答出来!
原文:https://juejin.cn/post/7101674091962171400