>[danger]请介绍一下Js中的单线程和事件循环 >[info]建议回答 * Js是单线程,但是浏览器是多线程。 * Js中采用了**事件循环**(Event Loop)来执行**异步任务**。 * 所以,**事件循环是一种异步编程模型**,事件循环会不断地从**任务队列**(Task Queue)中取出待处理的任务并执行,直到任务队列为空为止。任务可以分为两类:**宏任务**(Macro Task)和**微任务**(Micro Task)。 * **微任务会优先于宏任务执行** * [百度脑图:事件循环](https://naotu.baidu.com/file/5c774804acc0047a92171002cef27459?token=520c03781679fb20) >[info]技术详解 Js是单线程,但是浏览器是多线程。单线程是为了避免UI操作混乱,所有和UI操作相关的开发语言都应该是单线程。 JavaScript 是一门单线程的编程语言,它采用了**事件循环**(Event Loop)来执行**异步任务**。 ## 基本概念 - **事件循环是一种异步编程模型**,事件循环会不断地从任务队列(Task Queue)中取出待处理的任务并执行,直到任务队列为空为止。任务可以分为两类:宏任务(Macro Task)和微任务(Micro Task)。 - 宏任务包括了整体代码块、setTimeout、setInterval、setImmediate、I/O 操作等。当宏任务被添加到任务队列时,事件循环会检查当前是否有正在执行的宏任务,如果有,则继续执行当前宏任务;如果没有,则取出任务队列中的第一个宏任务,并执行它。 - 微任务包括了 Promise.then、MutationObserver 等。当微任务被添加到任务队列时,它们会优先于下一个宏任务执行。也就是说,当宏任务执行完毕后,如果存在微任务,则会立即执行所有的微任务,直到微任务队列为空为止。然后再执行下一个宏任务。 ## 事件循环流程 JavaScript 的事件循环流程如下: 1. 执行全局主线程代码,遇到宏任务时,将其放入宏任务队列中。 2. 遇到微任务时,将其放入微任务队列中。 3. 主线程代码执行完毕后,先执行所有微任务,直到微任务队列为空为止。 4. 取出宏任务队列中的第一个任务,执行它,并重复步骤 2 和步骤 3,直到宏任务队列为空为止。 ## 示例代码 以下是一个示例代码,展示了事件循环的执行过程: ~~~ 复制代码console.log('1'); setTimeout(() => { console.log('2'); Promise.resolve().then(() => { console.log('3'); }); }); Promise.resolve().then(() => { console.log('4'); setTimeout(() => { console.log('5'); }, 0); }); console.log('6'); // 输出结果: // 1 // 6 // 4 // 2 // 3 // 5 ~~~ 1. 首先,执行全局主线程代码,输出 `1` 和 `6`。然后,遇到微任务 `Promise.resolve().then(() => { console.log('4'); ... })`,将其放入微任务队列中。 2. 接着,执行宏任务 `setTimeout(() => { console.log('2'); ... })`,将其放入宏任务队列中,同时遇到微任务 `Promise.resolve().then(() => { console.log('3'); })`,将其放入微任务队列中。此时,微任务队列中有一个任务,宏任务队列中有一个任务。因为存在微任务,所以执行所有微任务,即输出 `4` 和 `3`。然后继续执行宏任务队列中的第一个任务,输出 `2`,并将另一个宏任务 `setTimeout(() => { console.log('5'); }, 0)` 放入宏任务队列中。 3. 最后,因为微任务队列为空,事件循环结束。输出结果为 `1, 6, 4, 2, 3, 5`。 >参考链接 - [脑图:事件循环](https://naotu.baidu.com/file/5c774804acc0047a92171002cef27459?token=520c03781679fb20)