先来看段代码
// 示例代码1console.log("start", 1)// 宏任务setTimeout(() => {setTimeout(() => {console.log("setTimeout", 12)}, 0)Promise.resolve().then(() => {console.log("Promise", 8)})}, 0)
Promise.resolve().then(() => { console.log("Promise,", 3) Promise.resolve().then(() => { console.log("Promise", 5) Promise.resolve().then(() => { console.log("Promise", 7) }) }) setTimeout(() => { console.log("setTimeout", 10) }, 0)})Promise.resolve().then(() => { console.log("Promise", 4) Promise.resolve().then(() => { console.log("Promise", 6) }) setTimeout(() => { console.log("setTimeout", 11) }, 0)})setTimeout(() => { console.log("setInerval", 9)}, 0);console.log("start2", 2)// 执行结果// start 1// start2 2// Promise 3// Promise 4// Promise 5// Promise 6// Promise 7// Promise 8// setInerval 9// setTimeout 10// setTimeout 11// setTimeout 12
- 为什么会出现这样的执行顺序呢?> 因为JS执行机制就是这样的 我也莫得办法。。。- JS执行机制> 提到js执行机制那就必须得提几个概念、宏任务、微任务、异步任务、同步任务,以及事件循环,在了解这些概念之前 先看一张示例图![image.png](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/fd8927ef8f2c437aaeab77ccc7f8f2b3~tplv-k3u1fbpfcp-watermark.image?)- 先说一下什么是宏任务、微任务、同步异步任务### 宏任务:- 整体的script代码- setTimeout- setInterval- setImmediate- I/O (比如Ajax操作从网络读取数据)- UI render### 微任务:- process.nextTick- Promise- Async/Await(实际就是promise)- MutationObserver(html5新特性)### 同步任务:> 示例代码1 console.log("start", 1) 就是一个同步任务### 异步任务:> setTimeout、setInterval、 I/O、Promise、Async/Await等等> 示例代码1 中setTimeout promis.then 都属于异步任务。且setTimeout 属于宏任务 promise.then 属于微任务#### 事件循环> 上述示例图中 这部分 宏任务循环执行就是事件循环> 宏任务=> 微任务 => 宏任务![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/938792bba12a47dea79bd8745acc747a~tplv-k3u1fbpfcp-watermark.image?)> 看到这里如果还不懂 没关系,我们来借助示例代码1 来理解- 首先 我们应该先明确一个执行概念,**在同步代码>微任务队列>宏任务队列,在同步代码执行完毕之后微任务优先级高于宏任务** 然后我们在区分哪些代码是同步 哪些代码是异步、在示例一代码中 除console 之外 其余的都是异步代码,所以可以明确两个同步代码的执行顺序```javascript console.log("start", 1)console.log("start2", 2)
明确了所有同步代码的执行顺序之后,我们在区分 哪些任务是微任务 与宏任务
微任务
// promise.then 属于微任务Promise.resolve().then(() => { console.log("Promise,", 3) setTimeout(() => { console.log("setTimeout", 8) }, 0) })// promise.then 属于微任务Promise.resolve().then(() => {console.log("Promise", 4)Promise.resolve().then(() => { console.log("Promise", 5)})setTimeout(() => { console.log("setTimeout", 9)}, 0)})
2. 宏任务```js// setTimeout属于宏任务setTimeout(() => { setTimeout(() => { console.log("setTimeout", 10) }, 0) Promise.resolve().then(() => { console.log("Promise", 6) })}, 0) // setTimeout属于宏任务setTimeout(() => { console.log("setInerval", 7)}, 0);
综上所述 当同步任务执行完毕之后 此时的任务队列应该是这样的
微任务:[Promise.resolve().then(() => { console.log("Promise,", 3) setTimeout(() => { console.log("setTimeout", 8) }, 0) }),Promise.resolve().then(() => { console.log("Promise", 4) Promise.resolve().then(() => { console.log("Promise", 5) }) setTimeout(() => { console.log("setTimeout", 9) }, 0)}), ] 宏任务:[setTimeout(() => { setTimeout(() => { console.log("setTimeout", 10) }, 0) Promise.resolve().then(() => { console.log("Promise", 6) })}, 0),setTimeout(() => { console.log("setInerval", 7)}, 0); ]
当同步任务执行完毕之后,接下来会执行微任务队列,微任务队列执行完毕之后,才会进入事件循环状态,执行宏任务
PS:当执行微任务时,微任务内含有宏任务,那么会将宏任务push到宏任务队列中,如果微任务中含有微任务将进行同步执行,代码如下
// 当微任务中含有宏任务 Promise.resolve().then(() => { console.log("Promise,", 3) // 此时遇到setTimeout不会立刻执行,setTimeout为宏任务,会push到宏任务中按序执行 setTimeout(() => { console.log("setTimeout", 8)
}, 0)})
// 当微任务中含有微任务 Promise.resolve().then(() => { console.log("Promise", 4) // 此刻遇到promise.then为微任务,立刻执行此微任务 Promise.resolve().then(() => { console.log("Promise", 5) }) // 此时遇到setTimeout不会立刻执行,setTimeout为宏任务,会push到宏任务中按序执行 setTimeout(() => { console.log("setTimeout", 9) }, 0) }),
- PS:**当执行宏任务时,宏任务内含有宏任务,那么会将宏任务push到宏任务队列中,如果宏任务中含有微任务将进行同步执行,代码如下**```jssetTimeout(() => {// 遇到宏任务 push到宏任务队列中 setTimeout(() => { console.log("setTimeout", 10) }, 0) // 遇到微任务,继续执行 Promise.resolve().then(() => { console.log("Promise", 6) })}, 0),
如果看到这还没能理解代码示例1中的执行顺序 也没关系,我们用js代码实现一下整个js执行机制
// javascriptCode 必做所有js代码// wTask 我们比做微任务队列// hTask 我们比做宏任务队列// Javascript 用来执行我们的js代码// codeList 值: key-代码类型 code-执行代码 child-宏任务或者微任务里的子任务// 将示例代码转化为得到javascriptCode如下 let javascriptCode = [{ key: 0, code: "start1" }, { key: 2, code: "", child: [ { key: 2, code: "setTimeout:12", }, { key: 1, code: "Promise:8", } ] }, { key: 1, code: "Promise:3", child: [ { key: 1, code: "Promise:5", child: [ { key: 1, code: "Promise:7", }, ] }, { key: 2, code: "setTimeout:10", } ] }, { key: 1, code: "Promise:4", child: [ { key: 1, code: "Promise:6", }, { key: 2, code: "setTimeout:11", } ] }, { key: 2, code: "setInerval:9", }, { key: 0, code: "start2:2", },]
接下来我们用一个javascript类 执行我们的javascriptCode
Promise.resolve().then(() => { console.log("Promise,", 3) Promise.resolve().then(() => { console.log("Promise", 5) Promise.resolve().then(() => { console.log("Promise", 7) }) }) setTimeout(() => { console.log("setTimeout", 10) }, 0)})Promise.resolve().then(() => { console.log("Promise", 4) Promise.resolve().then(() => { console.log("Promise", 6) }) setTimeout(() => { console.log("setTimeout", 11) }, 0)})setTimeout(() => { console.log("setInerval", 9)}, 0);console.log("start2", 2)// 执行结果// start 1// start2 2// Promise 3// Promise 4// Promise 5// Promise 6// Promise 7// Promise 8// setInerval 9// setTimeout 10// setTimeout 11// setTimeout 120原文:https://juejin.cn/post/7098324584155316232