Js - 运行机制 (Even Loop)node
JavaScript的一个语言特性(也是这门语言的核心)就是单线程。什么是单线程呢?简单地说就是同一时间只能作一件事,当有多个任务时,只能按照一个顺序一个完成了再执行下一个。promise
那为何JS是单线程的呢?浏览器
为了提升CPU的利用率,HTML5提出Web Worker标准,容许JavaScript脚本建立多个线程,可是子线程彻底受主线程控制,且不得操做DOM。因此这个标准并无改变JavaScript单线程的本质;多线程
任务队列 Task queue异步
在Javascript中,全部的任务分为两类:同步任务和异步任务
函数
同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;oop
异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务能够执行了,该任务才会进入主线程执行。post
简要说明:在这里说到了 ‘主线程’ 和 ‘任务队列’ ,我的简单理解: 主线程就是 Js 执行的线程 , 任务队列是异步任务暂时存放的一个事件队列;spa
在Js执行中,同步任务和异步任务分别进入不一样的执行"场所",同步的进入主线程,异步的进入 Event Table 并注册函数。 线程
当指定的事情完成时,Event Table 会将这个函数移入 Event Queue (事件队列)。
主线程内的任务执行完毕为空,会去 Event Queue 读取对应的函数,进入主线程执行。
上述过程会不断重复,也就是咱们常说的 Event Loop(事件循环)。
经过上边的描述,咱们来看一张图更加清晰的了解 Event Loop (事件循环) 机制
接下来咱们看一个例子:
setTimeout(function(){ console.log('1') }); new Promise(function(resolve){ console.log('2'); resolve(); }).then(function(){ console.log('3') }); console.log('4');
首先setTimeout 是异步进入 事件队列,而后 promise 的 then 也是异步 进入事件队列 ,
那么按照咱们上边说的Js执行机制,先走主线程的同步任务,打印2 ,而后4,紧跟着执行异步任务,也就是任务队列打印1,随后是 3 , 因此结果应该是 2,4,1,3, 事实真的是这样子嘛 ? 接着往下看 :
Js 中的宏任务和微任务 - 略记一下
macro-task(宏任务) :包括总体代码 script,setTimeout,setInterval
micro-task(微任务) : Promise,process.nextTick
(process.nextTick(callback)
相似node.js版的"setTimeout",在事件循环的下一次循环中调用 callback 回调函数)
咱们上边的 setTimeout 放到了 event queue 事件队列里 , promise 的 then 函数 也被放到了 event queue 事件队列里,然而杯具来了,这两个 queue 并非一个队列;
在 Js Event Loop 机制中
Promise 执行器中的代码会被主线程同步调用,可是 promise 的回调函数是基于微任务的
宏任务的优先级高于微任务
每个宏任务执行完毕都必须将当前的微任务队列清空
emmmm~~
如今咱们回到上边的例子中,由于 settimeout 是宏任务,虽然先执行的它,可是他被放到了宏任务的 event queue 里面,而后代码继续往下检查看有没有微任务,检测到 Promise 的 then 函数把它放入了微任务队列。等到主线进程的全部代码执行结束后。先从微任务
queue 里拿回调函数,而后微任务queue空了后再从宏任务的queue拿函数。
因此正确的执行结果固然是:2,4,3,1 ;
由此延申一下 事循环-宏任务-微任务 (Event Queue - Macro - Micro )关系图:
最后出一个小试题,看看你们是否真的理解到了 Js 的运行机制
试题借鉴 ssssyoki 答案及分析请前往 ssssyoki 博客。
console.log('1'); setTimeout(function() { console.log('2'); process.nextTick(function() { console.log('3'); }) new Promise(function(resolve) { console.log('4'); resolve(); }).then(function() { console.log('5') }) }) process.nextTick(function() { console.log('6'); }) new Promise(function(resolve) { console.log('7'); resolve(); }).then(function() { console.log('8') }) setTimeout(function() { console.log('9'); process.nextTick(function() { console.log('10'); }) new Promise(function(resolve) { console.log('11'); resolve(); }).then(function() { console.log('12') }) })