JavaScript運行機制的理解

0.前言

又是新的一年啊!


timg.jpeg

1.簡介

JavaScript 是腳本語言,JS也是單線程的耳高,因此同一時間只能做一件事,也就是說它一次僅能處理一個任務概荷。

思考題
  • JavaScript為什么是單線程的? 為什么需要異步? 單線程又是如何實現(xiàn)異步的呢?
  • JavaScript中的event loop()
  • 看一段代碼碌燕,想下正確的輸出順序
console.log(1)

Promise.resolve().then(function () {
   console.log(2)
})

new Promise(function(resolve, reject){
    console.log(3)
    resolve()
}).then(function () {
    console.log(4)
    setTimeout(function () {
        console.log(5)
    })
})

console.log(6)

setTimeout(function () {
    Promise.resolve().then(function () {
        console.log(7)
        setTimeout(function () {
            console.log(8)
        })
    })
})

2.概念

執(zhí)行上下文(Execution Context)

執(zhí)行上下文簡單來說就是一個執(zhí)行環(huán)境修壕。它有全局環(huán)境、函數(shù)環(huán)境和eval函數(shù)環(huán)境之分蓝谨。它會在javascript引擎執(zhí)行你的腳本的時候去創(chuàng)建青团。

執(zhí)行棧(Execution Stack)

執(zhí)行棧也就是常說的調(diào)用棧,它是一種擁有LIFO(后進先出)的數(shù)據(jù)結構缕题。它會存儲代碼運行時創(chuàng)建的執(zhí)行上下文

微任務(micro task)與宏任務(macro task)

javasript中的任務分為微任務和宏任務兩種胖腾,這兩種任務的執(zhí)行時機是不同的,因此區(qū)分js中哪些是宏任務锨阿,哪些是微任務則十分重要墅诡。我們常見的宏任務有:script任務桐智、setTimeoutajax等然磷,常見的微任務比較典型的是:Promise.resolve().then()刊驴、process.nextTick寡润、MutationObserver等梭纹。

事件循環(huán)(event loop)

javasript是單線程的致份,一次僅能處理一個任務。但js所在的宿主環(huán)境瞬沦,也就是我們所說的瀏覽器并不是單線程的(這里宿主環(huán)境僅討論瀏覽器)雇锡。它在遇到一些任務時锰提,比如說setTimeout芳悲、event listener等。它會告訴瀏覽器:老兄幫個忙谅年,事成后通知我一聲肮韧,小弟我先干別的事去了。瀏覽器會回應說:交給我吧超燃,小老弟拘领,事成后我放到任務隊列,自己去取啊届良。于是圣猎,javasript開始執(zhí)行script任務,執(zhí)行完了就開始檢查有沒有微任務啊为障,沒有的話就從任務隊列開始取宏任務執(zhí)行鳍怨,每執(zhí)行完一次宏任務,就去看看有沒有微任務声滥,有的話就執(zhí)行完成侦香,再執(zhí)行宏任務,如此往復憾赁。如下圖:

1.png

而準確的劃分方式是:

  • macro-task(宏任務):包括整體代碼script龙考,setTimeout矾睦,setInterval
  • micro-task(微任務):Promiseprocess.nextTick

3.回答思考題

JavaScript為什么是單線程的?

因為現(xiàn)在如果有兩個任務一個是刪除DOM節(jié)點缓溅,一個是增加DOM節(jié)點赁温,瀏覽器該如何執(zhí)行?所以JavaScript是單線程

為什么需要異步?

如果JavaScript中不存在異步,只能自上而下執(zhí)行,如果上一行解析時間很長,那么下面的代碼就會被阻塞酝陈,不向下執(zhí)行毁涉。
頁面出來,用戶看到覺得是“卡死了”穆壕,所以需要異步其屏。

JavaScript單線程又是如何實現(xiàn)異步的呢?

是通過的事件循環(huán)(event loop)實現(xiàn)異步的。

JavaScript中的event loop()

JavaScript的執(zhí)行機制是

  • 首先判斷JavaScript是同步還是異步,同步就進入主線程,異步就進入event table
  • 異步任務在event table中注冊函數(shù),當滿足觸發(fā)條件后,被推入event queue
  • 同步任務進入主線程后一直執(zhí)行,直到主線程空閑時,才會去event queue中查看是否有可執(zhí)行的異步任務,如果有就推入主線程中

了解了這幾個概念川背,再來看看javascript是怎么執(zhí)行代碼的就比較輕松愉快了。開始吧

console.log(1)

Promise.resolve().then(function () {
   console.log(2)
})

new Promise(function(resolve, reject){
    console.log(3)
    resolve()
}).then(function () {
    console.log(4)
    setTimeout(function () {
        console.log(5)
    })
})

console.log(6)

setTimeout(function () {
    Promise.resolve().then(function () {
        console.log(7)
        setTimeout(function () {
            console.log(8)
        })
    })
})

第一波先執(zhí)行宏任務

  • JavaScript引擎在執(zhí)行這段代碼的時候膨更,首先將全局執(zhí)行上下文壓入棧中,然后呢荚守,在執(zhí)行的時候會碰到console.log函數(shù)练般,將它壓入棧中,這個時候,直接執(zhí)行console函數(shù)敞贡,并輸出1摄职。然后console函數(shù)出棧
  • 繼續(xù)往下執(zhí)行,碰到了Promise.resolve().then(),先將Promise.resolve().then()壓入棧中,然后執(zhí)行Promise.resolve().then(),前面說過,這個then()函數(shù)是個微任務蛛倦,它會將傳入給它的回調(diào)函數(shù)加入到微任務隊列中。然后Promise.resolve().then()就出棧了及皂。
  • 接著執(zhí)行且改,遇到promise的構造函數(shù),這個構造函數(shù)是一個宏任務碍拆,會直接將傳遞給它的函數(shù)壓入棧中慨蓝。執(zhí)行console函數(shù)并輸出3,執(zhí)行完弧满,console函數(shù)出棧此熬,接著執(zhí)行resolve()函數(shù)滑进,并出棧扶关。然后繼續(xù)執(zhí)行then函數(shù)近哟,將傳遞給then函數(shù)的參數(shù)函數(shù)放到微任務隊列中:
  • 繼續(xù)來,繼續(xù)往下執(zhí)行疯淫。碰到console.log(6),二話不說戳玫,直接壓入棧中,執(zhí)行币绩,輸出6府阀,出棧,一氣呵成董瞻。
  • 接著田巴,引擎碰到了setTimeout函數(shù),這家伙是個宏任務抄伍,但同時它會將傳遞給它的函數(shù)管宵,加入到任務隊列中:

好了谍珊,到此第一波宏任務就全部執(zhí)行完畢虫给。接著素跺,引擎就會去看一下微任務隊列中有沒有任務坡锡,如果有的話燕雁,執(zhí)行它們鲸拥。

第二波先執(zhí)行微任務

  • 現(xiàn)在看到的是刑赶,微任務隊列中有兩個任務懂衩。按照隊列的先入先出規(guī)則,先從function () {console.log(2)}開始執(zhí)行牵敷。先是函數(shù)入棧法希,然后執(zhí)行函數(shù),輸出2毛肋,然后函數(shù)出棧屋剑。
    接著執(zhí)行下面這段代碼:
console.log(4)
setTimeout(function () {
   console.log(5)
})

先從 console.log(4)開始,先將它入棧孕讳,然后執(zhí)行它肄鸽,輸出4油啤,然后函數(shù)出棧。
接著執(zhí)行:

setTimeout(function () {
   console.log(5)
})

上面說過setTimeout是宏任務,加入到任務隊列中去逮诲。
繼續(xù)向下執(zhí)行

function(){
Promise.resolve().then(function () {
        console.log(7)
        setTimeout(function () {
            console.log(8)
        })
    })
}

這里執(zhí)行這個函數(shù)的時候遇到一個微任務幽告,將這個微任務添加到微任務隊列,這一波又執(zhí)行完了,接著就回去檢查微任務隊列中有沒有待執(zhí)行的任務齐唆,一看還真有兩個小可愛等待執(zhí)行冻河,于是沒什么好說的茉帅,直接擰出去就執(zhí)行堪澎。

第三波

  • 先是執(zhí)行console.log(7)味滞,然后輸出7。接著執(zhí)行setTimeout昨凡,將傳遞給他的任務添加到任務隊列中去
  • 最后就剩這兩個函數(shù)了攒暇,按照隊列的先入后出一次執(zhí)行吧,輸出5和8就轧。

最后看一下打印最后的結果就是1,3,6,2,4,7,5,8田度。你寫對了嗎?

4.總結
最后牢記兩點

  • JavaScript是單線程語言镇饺。
  • JavaScript的Event Loop是JS的執(zhí)行機制。
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末惋啃,一起剝皮案震驚了整個濱河市边灭,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌绒瘦,老刑警劉巖扣癣,帶你破解...
    沈念sama閱讀 221,273評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件父虑,死亡現(xiàn)場離奇詭異,居然都是意外死亡士嚎,警方通過查閱死者的電腦和手機烁焙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評論 3 398
  • 文/潘曉璐 我一進店門骄蝇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來九火,“玉大人,你說我怎么就攤上這事岔激∈顷” “怎么了?”我有些...
    開封第一講書人閱讀 167,709評論 0 360
  • 文/不壞的土叔 我叫張陵炫彩,是天一觀的道長絮短。 經(jīng)常有香客問我,道長杉允,這世上最難降的妖魔是什么席里? 我笑而不...
    開封第一講書人閱讀 59,520評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮奖磁,結果婚禮上,老公的妹妹穿的比我還像新娘署穗。我一直安慰自己案疲,他們只是感情好麻养,可當我...
    茶點故事閱讀 68,515評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著备畦,像睡著了一般。 火紅的嫁衣襯著肌膚如雪懂盐。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,158評論 1 308
  • 那天拌喉,我揣著相機與錄音尿背,去河邊找鬼。 笑死田藐,一個胖子當著我的面吹牛吱七,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播踊餐,決...
    沈念sama閱讀 40,755評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼市袖,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了苍碟?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,660評論 0 276
  • 序言:老撾萬榮一對情侶失蹤舷丹,失蹤者是張志新(化名)和其女友劉穎颜凯,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體症概,經(jīng)...
    沈念sama閱讀 46,203評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡早芭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,287評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了募壕。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,427評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡缰泡,死狀恐怖匀谣,靈堂內(nèi)的尸體忽然破棺而出资溃,到底是詐尸還是另有隱情,我是刑警寧澤溶锭,帶...
    沈念sama閱讀 36,122評論 5 349
  • 正文 年R本政府宣布趴捅,位于F島的核電站,受9級特大地震影響综芥,放射性物質發(fā)生泄漏。R本人自食惡果不足惜膀藐,卻給世界環(huán)境...
    茶點故事閱讀 41,801評論 3 333
  • 文/蒙蒙 一额各、第九天 我趴在偏房一處隱蔽的房頂上張望吧恃。 院中可真熱鬧,春花似錦痕寓、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽藐守。三九已至,卻和暖如春乾蓬,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背任内。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工死嗦, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人越除。 一個月前我還...
    沈念sama閱讀 48,808評論 3 376
  • 正文 我出身青樓摘盆,卻偏偏與公主長得像饱苟,于是被迫代替她去往敵國和親孩擂。 傳聞我的和親對象是個殘疾皇子类垦,可洞房花燭夜當晚...
    茶點故事閱讀 45,440評論 2 359

推薦閱讀更多精彩內(nèi)容