您好,登錄后才能下訂單哦!
這篇文章主要介紹“JS前端宏任務微任務及Event Loop如何使用”,在日常操作中,相信很多人在JS前端宏任務微任務及Event Loop如何使用問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”JS前端宏任務微任務及Event Loop如何使用”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
首先我們要了解javascript是一個單線程的腳本語言,也就是說我們在執(zhí)行代碼的過程中不會出現(xiàn)同時進行兩個進程(執(zhí)行兩段代碼)。
Javascript語言將任務的執(zhí)行模式分成兩種:同步(Synchronous)和異步(Asynchronous)。
同步:一個進程在執(zhí)行某個請求的時候,若該請求需要一段時間才能返回信息,那么這個進程將會一直等待下去,直到收到返回信息才繼續(xù)執(zhí)行下去。
異步:進程不需要一直等下去,而是繼續(xù)執(zhí)行下面的操作,不管其他進程的狀態(tài)。當有消息返回時系統(tǒng)會通知進程進行處理,這樣可以提高執(zhí)行的效率。
進程:狹義上,就是正在運行的程序的實例。廣義上,進程是一個具有一定獨立功能的程序關于某個數(shù)據集合的一次運行活動。描述的是CPU在運行指令及加載和保存上下文所需要的時間。
線程:是程序中一個單一的順序控制流程。進程內一個相對獨立的、可調度的執(zhí)行單元,是系統(tǒng)獨立調度和分派CPU的基本單位。指運行中的程序的調度單位。
執(zhí)行棧:V8(谷歌瀏覽器引擎)內部維護出來的一個用來存放函數(shù)的執(zhí)行上下文環(huán)境的一個棧結構。
相信有不少人和我有著一樣的疑惑,既然javascript是單線程的腳本語言,那么他有什么優(yōu)勢呢,為什么不寫成多進程的呢?
單線程不僅可以節(jié)省內存同時也可以節(jié)省上下文切換時間;
不會和渲染線程沖突(如果JS是雙線程的,當頁面渲染線程還在執(zhí)行時,JS已經將渲染頁面的參數(shù)修改,就會導致頁面渲染出現(xiàn)問題)
(macro)task,可以理解是每次執(zhí)行棧執(zhí)行的代碼就是一個宏任務(包括每次從事件隊列中獲取一個事件回調并放到執(zhí)行棧中執(zhí)行)。
I/O
UI-rendering (頁面渲染)
script
setTimeout
setInterval
setImmediate (node環(huán)境下是,而瀏覽器環(huán)境下不是)
requestAnimationFrame (在瀏覽器環(huán)境是,而node環(huán)境不是)
requestAnimationFrame在MDN的定義為,下次頁面重繪前所執(zhí)行的操作,而重繪也是作為宏任務的一個步驟來存在的,且該步驟晚于微任務的執(zhí)行。
microtask,可以理解是在當前 task 執(zhí)行結束后立即執(zhí)行的任務。也就是說,在當前task任務后,下一個task之前,在渲染之前。
所以它的響應速度相比setTimeout(setTimeout是task)會更快,因為無需等渲染。也就是說,在某一個macrotask執(zhí)行完后,就會將在它執(zhí)行期間產生的所有microtask都執(zhí)行完畢(在渲染前)。
process.nextTick (node環(huán)境下是,而瀏覽器環(huán)境下不是)
promise.then
MutationObserver (在瀏覽器環(huán)境是,而node環(huán)境不是)
上面我們講了半天宏任務、微任務等各種任務的執(zhí)行那么vent-Loop到底是個啥?
javascript是一個單進程的語言,同一時間不能處理多個任務,所以什么時候執(zhí)行宏任務什么時候執(zhí)行微任務呢?于是乎我們需要Event Loop-事件循環(huán)機制(計算機系統(tǒng)的一種運作機制)這樣一個判斷邏輯存在。
同步代碼: js為腳本語言,對于同步代碼來說,自上而下進行解釋執(zhí)行。
異步代碼: 對于一個任務,分為多個片段來進行執(zhí)行, 先執(zhí)行一段,如果碰到比較耗時間的操作,比如本地或者網絡io請求。 第一段開始進行io之后,把執(zhí)行權交由其他任務,當io完成后再來執(zhí)行后半段的任務(io操作比較耗時,在系統(tǒng)進行io時,主線程是空閑的)
1. 首先執(zhí)行同步代碼,這屬于宏任務;
2. 當執(zhí)行完所有的同步代碼后,執(zhí)行棧為空,檢查是否有異步代碼要執(zhí)行;
3. 執(zhí)行微任務;
4. 執(zhí)行完微任務后,有必要的情況下會渲染頁面;
5. 開啟下一輪 Event Loop,執(zhí)行宏任務中的代碼;
代碼在執(zhí)行過程中,遇到異步代碼,會將異步代碼用隊列裝起來(掛起)
實戰(zhàn)出真理,我們用一個????感受一下 console.log('start'); // 1 function foo(){ console.log('foo'); } foo() // 2 setTimeout(function() { //異步代碼中的宏任務,先掛起 console.log('setTimeout'); // 7 },1000) new Promise(resolve =>{ console.log('promise'); // 3 resolve() }) .then(function() { //異步代碼中的微任務,先掛起 console.log('promise1');// 5 }) .then(function() { //異步代碼中的微任務,先掛起 console.log('promise2');// 6 }) console.log('end'); // 4
我們跟著實行順序來分析,第一步首先執(zhí)行同步代碼,所以首先打印出來‘start’,調用函數(shù)foo打印出來‘foo’,執(zhí)行Promise函數(shù)打印出來‘promise’,最后打印出來‘end’同步代碼就執(zhí)行完畢,再檢查是否有異步代碼要執(zhí)行,第三步執(zhí)行微任務,所以先打印出第一微任務列表中的‘promise1’,緊接著打印第二微任務列表中的‘promise2’純js不用渲染頁面,最后開啟下一輪的Event-Loop,執(zhí)行宏任務中的代碼,而setTimeout就是異步代碼中的宏任務所以最終打印出來‘setTimeout’,最后我們來看看在谷歌瀏覽器中的打印效果。
這里有個小細節(jié),如果將定時器setTimeout的時間設置為0呢?結果其實還是一樣的,setTimeout不會因為時間而改變執(zhí)行順序,因為它仍然是異步代碼中的宏任務,不會因為延遲執(zhí)行的時間而改變。
到此,關于“JS前端宏任務微任務及Event Loop如何使用”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續(xù)學習更多相關知識,請繼續(xù)關注億速云網站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。