单线程和异步
首先我们需要了解,JavaScript代码的运行是单线程,采用单线程模式工作的原因也很简单,最早就是在页面中实现DOM操作,如果使用多线程,就会造成复杂的线程问题,如果一个线程修改了某个元素,另一个线程又删除了额这个元素,浏览器渲染就会出现问题。 优点:安全、简单 缺点:遇到任务量大的操作,会阻塞,后面的任务会长时间等待,出现假死的情况 为了解决阻塞的问题,JavaScript将任务的执行模式分为了两种,同步模式(Synchronous)和异步模式(Asynchronous)
事件循环概述
js的执行机制就是事件循环。js在执行时,有以下几个主要部分参与了事件循环。
- 执行栈,用于创建执行环境,执行js代码
- 异步处理模块,用来处理异步事件
- 任务队列,包括宏任务队列和微任务队列,用来控制消息的生产消费 事件循环的过程为:当执行栈空的时候,就会从任务队列中,取任务来执行。共分3步:
- 取一个宏任务来执行,执行完毕后,下一步
- 按序执行当前微任务队列中的所有任务,微任务队列为空时,下一步
- 更新UI渲染 其中,UI渲染会根据浏览器的逻辑,决定要不要马上执行更新,不一定在本次循环中立即执行。因此,js的执行会阻塞UI渲染。
任务队列
宏任务队列和微任务队列
- 宏任务队列可以有多个,微任务队列只有一个
- 宏任务包括script(全局任务),setTimeout,setInterval,setImmediate,I/O,UI rendering。微任务有process.nextTick,Promise,Object.observer,Mutation Observer。
- 宏任务队列有优先级之分。每次js引擎从宏任务队列中取宏任务时,会按照优先级选择宏任务队列,若高优先级的宏任务队列中没有任务时,才会到低级的宏任务队列中去取任务。
执行过程
首先,ks引擎从宏任务队列中取任务,因为script(全局)宏任务队列的优先级最高,因此先将这个任务取出(这个任务是当前所有可执行脚本),并利用执行栈执行这些脚本。在执行过程中,会产生一些异步操作,将其交由异步处理模块处理。异步处理模块会产生一系列异步回调,加入到任务队列中。当前执行栈执行完(栈为空)时,再执行微任务队列中的所有任务。执行完后,再根据优先级从宏任务队列中取出一个任务执行,然后再从微任务队列中取任务执行直至微任务队列为空。循环反复。