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