關于js的事件循環(huán)機制剖析
前言
眾所周知, JavaScript是單線程這一核心,可是瀏覽器又能很好的處理異步請求,那么到底是為什么呢?其中的原理與事件循環(huán)機制大有關系。
在探索事件循環(huán)之前,我們得先了解瀏覽器執(zhí)行線程~~
瀏覽器的渲染進程是多線程的,瀏覽器每一個tab標簽都代表一個獨立的進程,其中瀏覽器內核屬于瀏覽器多進程中的一種,主要負責頁面渲染,腳本執(zhí)行,事件處理等。其包含的線程有以下幾種
GUI 渲染線程:負責渲染頁面,解析 HTML,CSS 構成 DOM 樹;
JS 引擎線程:解釋執(zhí)行代碼、用戶輸入和網絡請求;
事件處理線程:click、mouse等交互事件發(fā)生后將事件函數放入隊列;
定時器觸發(fā)線程:等時間結束后執(zhí)行函數推入任務隊列中;
http網絡請求線程:處理用戶的get、post請求,返回結果推入任務隊列中。
了解了瀏覽器渲染流程,還要了解JS的運行機制。JS的運行機制就是事件循環(huán)
執(zhí)行棧
JS運行的環(huán)境稱之為宿主環(huán)境。
執(zhí)行棧:call stack,一個數據結構,用于存放各種函數的執(zhí)行環(huán)境,每一個函數執(zhí)行之前,它的相關信息會加入到執(zhí)行棧。函數調用之前,創(chuàng)建執(zhí)行環(huán)境,然后加入到執(zhí)行棧;函數調用之后,銷毀執(zhí)行環(huán)境。
事件循環(huán)
js中所有的任務可以分為同步任務和異步任務,同步任務是立即執(zhí)行的任務,同步任務一般會直接進入到主線程中執(zhí)行;而異步任務,就是異步執(zhí)行的任務,比如ajax網絡請求,setTimeout 定時函數等都屬于異步任務,異步任務會通過任務隊列(先進先出)的機制來進行協(xié)調。同步和異步任務分別進入不同的執(zhí)行環(huán)境,同步的進入主線程,即主執(zhí)行棧,異步的進入任務隊列。主線程內的任務執(zhí)行完畢為空,會去任務隊列讀取對應的任務,推入主線程執(zhí)行。 這種不斷重復就是我們說的 Event Loop (事件循環(huán))。具體流程如下圖。
在事件循環(huán)中,每進行一次循環(huán)操作稱為tick,每一次 tick 的任務鍵的步驟可以總結如下:1.執(zhí)行一個宏任務(棧中沒有就從事件隊列中獲取);2.執(zhí)行過程中如果遇到微任務,就將它添加到微任務的任務隊列中;3.宏任務執(zhí)行完畢后,立即執(zhí)行當前微任務隊列中的所有微任務(依次執(zhí)行);4.當前宏任務執(zhí)行完畢,開始檢查渲染,然后GUI線程接管渲染;5.渲染完畢后,JS線程繼續(xù)接管,開始下一個宏任務(從事件隊列中獲?。?/p>
宏任務主要包含:script( 整體代碼)、setTimeout、setInterval、I/O、UI 交互事件、setImmediate(Node.js 環(huán)境)
微任務主要包含:Promise、MutaionObserver、process.nextTick(Node.js 環(huán)境)
事件循環(huán)例子
console.log('script start'); //整體 script 作為第一個宏任務進入主線程,遇到 console.log,輸出 script start setTimeout(function() { console.log('setTimeout'); }, 0); //遇到 setTimeout,其回調函數被分發(fā)到宏任務 Event Queue 中 Promise.resolve().then(function() { console.log('promise1'); }).then(function() { console.log('promise2'); }); //遇到 Promise,其 then函數被分到到微任務 Event Queue 中,記為 then1,之后又遇到了 then 函數,將其分到微任務 Event Queue 中,記為 then2 console.log('script end'); //遇到 console.log,輸出 script end
如此,Event Queue(事件隊列)中存在三個任務:宏任務:setTimeout 微任務:then1、then2。執(zhí)行微任務首先then1,輸出 promise1, 然后執(zhí)行 then2,輸出 promise2,這樣就清空了所有微任務
執(zhí)行 setTimeout 任務,輸出 setTimeout 至此,輸出的順序是:script start, script end, promise1, promise2, setTimeout
總結:
JavaScript 是一門單線程語言,異步操作都是放到事件循環(huán)隊列里面,等待主執(zhí)行棧來執(zhí)行的,并沒有專門的異步執(zhí)行線程。
到此這篇關于js的事件循環(huán)機制的文章就介紹到這了,更多相關js事件循環(huán)內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
JavaScript實現AOP詳解(面向切面編程,裝飾者模式)
下面小編就為大家分享一篇JavaScript實現AOP的方法(面向切面編程,裝飾者模式),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2017-12-12百度坐標(BD09)、國測局坐標(火星坐標,GCJ02)、和WGS84坐標系之間的轉換
這篇文章主要介紹了百度坐標(BD09)、國測局坐標(火星坐標,GCJ02)、和WGS84坐標系之間的轉換的相關資料,需要的朋友可以參考下2016-02-02