摘要:深入理解引擎的執(zhí)行機制最近在反省,很多知識都是只會用,不理解底層的知識。在閱讀之前,請先記住兩點是單線程語言的是的執(zhí)行機制。所以,是存在異步執(zhí)行的,比如單線程是怎么實現(xiàn)異步的場景描述通過事件循環(huán),所以說,理解了機制,也就理解了的執(zhí)行機制啦。
深入理解js引擎的執(zhí)行機制
最近在反省,很多知識都是只會用,不理解底層的知識。所以在開發(fā)過程中遇到一些奇怪的比較難解決的bug,在思考的時候就會收到限制。所以,在這里一點一點補充基礎知識吧。
在閱讀之前,請先記住兩點:js是單線程語言
js的Event Loop是js的執(zhí)行機制。深入理解js的執(zhí)行,就等與深入理解js的Event Loop
好啦,下面進入正題
1. 靈魂三問:js為什么是單線程的?為什么需要異步?單線程又是怎么實現(xiàn)異步的呢?技術的出現(xiàn),都跟現(xiàn)實世界里的場景密切相關。同樣的,我們就結合現(xiàn)實場景,來回答這三個問題。
(1)js為什么是單線程的?
????????js是一種腳本語言,腳本語言是為了縮短傳統(tǒng)的編寫-編譯-鏈接-運行過程而創(chuàng)建的計算機編程語言,腳本語言不需要編譯,可以直接用,由解釋器來負責解釋。
????????js最初被設計用在瀏覽器中,那么想象一下,如果瀏覽器中的js是多線程的。。。
場景描述:
????????現(xiàn)在有兩個進程:process1和process2,由于是多線程的js,所以它們對同一個DOM同時進行操作process1刪除了該DOM,而process2編輯了該DOM,同時下達了兩個矛盾的命令,你這讓瀏覽器怎么執(zhí)行呢?
????????這樣一想,是不是就理解了js為什么被設計成單線程了吧~~~
(2)js為什么是異步的?
場景描述:
????????如果js不存在異步,只能自上而下執(zhí)行,如果上一行執(zhí)行時間很長,比如說沒有網(wǎng)了,那么下面的代碼就會被阻塞,對于用戶來說,阻塞就意味著“卡死”,這樣導致用戶體驗很差。由于這個“缺陷”,導致JavaScript的所有網(wǎng)絡操作,瀏覽器事件,都必須是異步執(zhí)行。
????????所以,js是存在異步執(zhí)行的,比如setTimeout、setInterval、ajax、promise
(3)單線程是怎么實現(xiàn)異步的?
場景描述:
????????通過Event Loop(事件循環(huán)),所以說,理解了Event Loop機制,也就理解了js的執(zhí)行機制啦。
舉個栗子:觀察下它的執(zhí)行機制
console.log(1) setTimeout(function(){ console.log(2) },0); console.log(3)
毫無疑問:運行結果是1 3 2
也就是說:setTimeout里的函數(shù)并沒有立即執(zhí)行,而是延遲了一段時間,滿足一定條件后才去執(zhí)行的,我們叫做異步代碼。
所以這里我們首先知道了js里的一種分類方式,就是將任務分為:同步任務和異步任務。
按照這種分類方式:js的執(zhí)行機制是
首先判斷js是同步的還是一步的,同步的就進入主進程,異步的就進入event table(事件表)
異步任務在Event table中注冊函數(shù),當滿足觸發(fā)條件后,被推入event queue(事件隊列)
同步任務進入主線程后一直執(zhí)行,直到主線程空閑時,才會去event queue中查看是否有可執(zhí)行的異步任務,如果有就推入主進程中
以上三步循環(huán)執(zhí)行,這就是Event Loop
所以上面的栗子,你是否可以描述它的執(zhí)行順序了呢?
console.log(1) //是同步任務,放進主進程里 setTimeout(function(){ //是異步任務,放進event table,0s之后被推入event queue里 console.log(2) },0); console.log(3) //是同步任務,放進主進程里 //當1、3在瀏覽器控制臺被打印后,主線程去event queue中查看是否有可執(zhí)行的函數(shù),執(zhí)行setTimeout里的函數(shù)。3. js中的Event Loop第二課
所以,上面關于Event Loop就是我對js執(zhí)行機制的理解,是不是很簡單呢。。。。
慢著!看看下面的這段代碼
又一個栗子:
setTimeout(function(){ console.log("定時器開始啦~~~"); }) new Promise(function(resolve){ console.log("馬上執(zhí)行for循環(huán)啦"); for(var i=0;i<10000;i++){ i==99&&resolve(); } }).then(function(){ console.log("執(zhí)行then函數(shù)啦") }); console.log("表演完畢!");
有沒有很熟悉,好像面試過程中經(jīng)常碰見這種問題呀~~~
現(xiàn)在,我們按照上面學到的js執(zhí)行機制去分析一下下
setTimeout(function(){ //是異步任務,被放進event table中 console.log("定時器開始啦~~~"); }) new Promise(function(resolve){ //是同步任務,被放進主進程中,直接執(zhí)行 console.log("馬上執(zhí)行for循環(huán)啦"); for(var i=0;i<10000;i++){ i==99&&resolve(); } }).then(function(){ //是異步任務,被放進event table中 console.log("執(zhí)行then函數(shù)啦") }); console.log("表演完畢!"); //是同步任務,被放進主進程中,直接執(zhí)行
運行結果是:【馬上執(zhí)行for循環(huán)啦----表演完畢!----執(zhí)行then函數(shù)啦----定時器開始啦~~~】
那么,難道是異步任務的執(zhí)行順序不是前后順序,而是另有規(guī)定?事實上,按照同步和異步的劃分方式,并不準確。
所以這里我們首先知道了js里的一種分類方式,就是將任務分為:同步任務和異步任務。
叨叨了半天,原來都是一些“假大空”的東西,搞什么搞嘛,哼?。?!
準確的劃分方式是:
macro-task(宏任務):包括整體代碼script、setTimeout、setInterval
micro-task(微任務):Promise、process.nextTick
按照這種分類方式:js的執(zhí)行機制就是
執(zhí)行一個宏任務,執(zhí)行過程中如果遇到微任務,就將其放在微任務的event queue里
當前宏任務執(zhí)行完成后,會查看微任務的event queue,并將里面的全部微任務依次執(zhí)行完。
重復以上兩個步驟,結合Event Loop第一課和Event Loop第二課,就是更為準確的js執(zhí)行機制了。
嘗試按照剛才學到的執(zhí)行機制,去分析第二個栗子:
setTimeout(function(){ console.log("定時器開始啦~~~"); }) new Promise(function(resolve){ console.log("馬上執(zhí)行for循環(huán)啦"); for(var i=0;i<10000;i++){ i==99&&resolve(); } }).then(function(){ console.log("執(zhí)行then函數(shù)啦") }); console.log("表演完畢!"); //首先執(zhí)行script中的宏任務; //遇到setTimeout,放進宏任務的event queue中; //遇到new Promise直接執(zhí)行,打印“馬上執(zhí)行for循環(huán)啦”; //遇到then方法,是微任務,被放進微任務的event queue //執(zhí)行打印“表演完畢!”,本輪宏任務執(zhí)行完畢; //查看本輪微任務,發(fā)現(xiàn)then方法里的函數(shù),執(zhí)行打印“執(zhí)行then函數(shù)啦” //到此,本輪Event Loop全部完成 //下一輪循環(huán)里,先執(zhí)行一個宏任務,發(fā)現(xiàn)宏任務的event queue中有一個setTimeout中的函數(shù),打印“定時器開始啦”
運行結果是:【馬上執(zhí)行for循環(huán)啦----表演完畢!----執(zhí)行then函數(shù)啦----定時器開始啦~~~】
4.談談setTimeout下面這段setTimeout代碼是什么意思?我們一般說:“3s后,會執(zhí)行setTimeout里的函數(shù)”
setTimeout(function(){ console.log("執(zhí)行了"); },3000)
但是這種說法并不嚴謹,準確的解釋是:
????????3s后,setTimeout里的函數(shù)會被推入到event queue中,而event queue(事件隊列)里的任務,只有在主線程空閑時才會執(zhí)行。
所以:只有在滿足
3s后
主線程空閑
這兩個條件同時滿足,才會在3s后執(zhí)行該函數(shù)。如果主線程執(zhí)行內(nèi)容很多,執(zhí)行時間超過3s,比如執(zhí)行了10s,那么這個函數(shù)只有在10s后執(zhí)行啦
到此,js引擎的執(zhí)行機制解讀完啦,前端的水很深,慢慢摸著吧
感謝文章的提供者:ziwei3749
文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://systransis.cn/yun/93481.html
摘要:深入理解引擎的執(zhí)行機制靈魂三問為什么是單線程的為什么需要異步單線程又是如何實現(xiàn)異步的呢中的中的說說首先請牢記點是單線程語言的是的執(zhí)行機制。 深入理解JS引擎的執(zhí)行機制 1.靈魂三問 : JS為什么是單線程的? 為什么需要異步? 單線程又是如何實現(xiàn)異步的呢? 2.JS中的event loop(1) 3.JS中的event loop(2) 4.說說setTimeout 首先,請牢記2...
摘要:當這些異步任務發(fā)生的時候,它們將會被放入瀏覽器的事件任務隊列中去,等到運行時執(zhí)行線程空閑時候才會按照隊列先進先出的原則被一一執(zhí)行,但終究還是單線程。 瀏覽器是多進程的 showImg(https://segmentfault.com/img/remote/1460000019706956?w=815&h=517); Browser進程: 瀏覽器的主進程(負責協(xié)調、主控),只有一個。 負...
摘要:當這些異步任務發(fā)生的時候,它們將會被放入瀏覽器的事件任務隊列中去,等到運行時執(zhí)行線程空閑時候才會按照隊列先進先出的原則被一一執(zhí)行,但終究還是單線程。 瀏覽器是多進程的 showImg(https://segmentfault.com/img/remote/1460000019706956?w=815&h=517); Browser進程: 瀏覽器的主進程(負責協(xié)調、主控),只有一個。 負...
摘要:引擎對堆內(nèi)存中的對象進行分代管理新生代存活周期較短的對象,如臨時變量字符串等。內(nèi)存泄漏對于持續(xù)運行的服務進程,必須及時釋放不再用到的內(nèi)存。 (關注福利,關注本公眾號回復[資料]領取優(yōu)質前端視頻,包括Vue、React、Node源碼和實戰(zhàn)、面試指導) 本周正式開始前端進階的第一期,本周的主題是調用堆棧,今天是第4天。 本計劃一共28期,每期重點攻克一個面試重難點,如果你還不了解本進階計劃...
摘要:圖片轉引自的演講和兩個定時器中回調的執(zhí)行邏輯便是典型的機制。異步編程關于異步編程我的理解是,在執(zhí)行環(huán)境所提供的異步機制之上,在應用編碼層面上實現(xiàn)整體流程控制的異步風格。 問題背景 在一次開發(fā)任務中,需要實現(xiàn)如下一個餅狀圖動畫,基于canvas進行繪圖,但由于對于JS運行環(huán)境中異步機制的不了解,所以遇到了一個棘手的問題,始終無法解決,之后在與同事交流之后才恍然大悟。問題的根節(jié)在于經(jīng)典的J...
閱讀 2580·2023-04-25 17:27
閱讀 1887·2019-08-30 15:54
閱讀 2416·2019-08-30 13:06
閱讀 3022·2019-08-30 11:04
閱讀 800·2019-08-29 15:30
閱讀 770·2019-08-29 15:16
閱讀 1801·2019-08-26 10:10
閱讀 3646·2019-08-23 17:02