macrotask和microtask以及EventLoop的介绍
前言
提起js,有這么幾個概念非了解不可。單線程 、回調(diào)函數(shù)、非阻塞、執(zhí)行上下文、調(diào)用棧、上下文、事件循環(huán)、任務(wù)隊(duì)列。
單線程
one thread = one call stack == one thing at a time 解釋來講就是單線程意味著只有一個調(diào)用棧,在同一時刻只能做一件事兒
執(zhí)行上下文
執(zhí)行上下文就是當(dāng)前JavaScript代碼被解析和執(zhí)行是所在環(huán)境的抽象概念,JavaScript中運(yùn)行任何的代碼都是在執(zhí)行上下文中運(yùn)行。
執(zhí)行上下文的類型,總共有三類 1.全局執(zhí)行上下文:這是默認(rèn)的,最基礎(chǔ)的執(zhí)行上下文。不在任何函數(shù)中的代碼都位于全局執(zhí)行上下文中。共有兩個過程: - .創(chuàng)建有全局對象,在瀏覽器中這個全局對象就是window對象。 - .將this指針指向這個全局對象。一個程序中只能存在一個執(zhí)行上下文。 2.函數(shù)執(zhí)行上下文:每次調(diào)用函數(shù)時,都會為該函數(shù)創(chuàng)建一個新的執(zhí)行上下文。每個函數(shù)都擁有自己的執(zhí)行上下文,但是只有在函數(shù)被調(diào)用的時候才會被創(chuàng)建。一個程序中可以存在多個函數(shù)執(zhí)行上下文。 3.Eval函數(shù)執(zhí)行上下文:運(yùn)行在eval函數(shù)中的代碼也獲得了自己的執(zhí)行上下文(不建議使用)
(執(zhí)行棧)調(diào)用棧
執(zhí)行棧,也叫調(diào)用棧,用于存儲在代碼執(zhí)行期間創(chuàng)建的所有執(zhí)行上下文。 當(dāng)JavaScript引擎首次讀取腳本時,會創(chuàng)建一個全局執(zhí)行上下文并將其Push到當(dāng)前執(zhí)行棧中。每當(dāng)發(fā)生函數(shù)調(diào)用時,引擎都會為該函數(shù)創(chuàng)建一個新的執(zhí)行上下文并Push到當(dāng)前執(zhí)行棧的棧頂
任務(wù)隊(duì)列、macrotask、mircotask
同步任務(wù)和異步任務(wù)
因 js是單線程語言 , 存在大量的IO等耗時操作,所以有“同步任務(wù)”和“異步任務(wù)”的區(qū)分 同步任務(wù)
在主線程上排隊(duì)執(zhí)行的任務(wù),前一個任務(wù)執(zhí)行完畢,才能執(zhí)行后一個任務(wù); 異步任務(wù) 不進(jìn)入主線程、而進(jìn)入”任務(wù)隊(duì)列”(task queue)的任務(wù),只有”任務(wù)隊(duì)列”通知主線程,某個異步任務(wù)可以執(zhí)行了,該任務(wù)才會進(jìn)入主線程執(zhí)行。 總之 只要主線程空了,就會去讀取”任務(wù)隊(duì)列”,這就是JavaScript的運(yùn)行機(jī)制,這個過程是循環(huán)往復(fù)的,所以也叫做Event Loop事件循環(huán)
macrotask、mircotask隊(duì)列
microtasks:
- process.nextTick
- promise
- Object.observe
- MutationObserver
macrotasks:
- setTimeout
- setInterval
- setImmediate
- I/O
- UI渲染
一個事件循環(huán)有一個或多個任務(wù)隊(duì)列,一個任務(wù)隊(duì)列是任務(wù)的集合 whatwg規(guī)范:html.spec.whatwg.org/multipage/w…
- task queue 就是 macrotask queue
- 每一個 event loop 都有一個 microtask queue
- task queue == macrotask queue != microtask queue
- 一個任務(wù) task 可以放入 macrotask queue 也可以放入 microtask queue 中
理解了這些定義之后,再看執(zhí)行原理:
事件循環(huán)的順序,決定了JavaScript代碼的執(zhí)行順序。它從script(整體代碼)開始第一次循環(huán)。之后全局上下文進(jìn)入函數(shù)調(diào)用棧。直到調(diào)用棧清空(只剩全局),然后執(zhí)行所有的micro-task。當(dāng)所有可執(zhí)行的micro-task執(zhí)行完畢之后。循環(huán)再次從macro-task開始,找到其中一個任務(wù)隊(duì)列執(zhí)行完畢,然后再執(zhí)行所有的micro-task,這樣一直循環(huán)下去。
更為形象的顯示代碼的執(zhí)行過程,請看https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/
還要注意一點(diǎn):
包裹在一個 script 標(biāo)簽中的js代碼也是一個 task 確切說是 macrotask。
事件循環(huán)
執(zhí)行棧中執(zhí)行完之后會從任務(wù)隊(duì)列中讀取一個task進(jìn)行執(zhí)行,這個過程是循環(huán)的,稱之為 "事件循環(huán)"
非阻塞
遇到異步操作,主線程會繼續(xù)處理后面的代碼,當(dāng)異步操作完成以后在任務(wù)隊(duì)列(task)中添加事件
引用了:blog.csdn.net/sjn0503/art…
轉(zhuǎn)載于:https://juejin.im/post/5d0788a9e51d45773e418a79
總結(jié)
以上是生活随笔為你收集整理的macrotask和microtask以及EventLoop的介绍的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 全球最大的苹果硬件收藏之一将拍卖,含 5
- 下一篇: [转]DPM2012系列之十三:如何清理