異步無(wú)處不在:同步模式和異步模式(一)
嗨,我是你穩(wěn)定更新、持續(xù)輸出的勾勾。

在 JS 代碼中,異步無(wú)處不在,比如 Ajax 通信,Node 中的文件讀寫(xiě)等等。而只有搞清楚異步編程的原理和概念,才能在 JS 的世界中任意馳騁,隨便撒歡。
單線程 JavaScript 異步方案
首先我們要了解,JavaScript 代碼的運(yùn)行是單線程。
采用單線程模式工作的原因也很簡(jiǎn)單,最早是為了在頁(yè)面中實(shí)現(xiàn) Dom 操作。如果采用多線程,就會(huì)造成復(fù)雜的線程同步問(wèn)題。如果一個(gè)線程修改了某個(gè)元素,另一個(gè)線程又刪除了這個(gè)元素,瀏覽器渲染就會(huì)出現(xiàn)問(wèn)題。
單線程的含義就是,JS 執(zhí)行環(huán)境中負(fù)責(zé)執(zhí)行代碼的線程只有一個(gè)。類似于只有一個(gè)人干活。他一次只能做一個(gè)任務(wù),如果有多個(gè)任務(wù)自然是要排隊(duì)的。
優(yōu)點(diǎn):安全,簡(jiǎn)單。
缺點(diǎn):遇到任務(wù)量大的操作,會(huì)阻塞。后面的任務(wù)會(huì)長(zhǎng)時(shí)間等待,出現(xiàn)假死的情況。

為了解決阻塞的問(wèn)題,Javascript 將任務(wù)的執(zhí)行模式分成了兩種,同步模式( Synchronous)和 異步模式( Asynchronous)。
同步模式與異步模式
在程序中,代碼依次執(zhí)行,后面的任務(wù)需要等待前面任務(wù)執(zhí)行結(jié)束后,才會(huì)執(zhí)行。同步并不是同時(shí)執(zhí)行,而是排隊(duì)執(zhí)行。
先來(lái)看一段代碼:
console.log('global?begin')function?bar?()?{??console.log('bar?task')}function?foo?()?{??console.log('foo?task')??bar()}foo()console.log('global?end')
用動(dòng)畫(huà)形式展現(xiàn)下同步代碼的執(zhí)行過(guò)程:

如圖所示,代碼會(huì)按照既定的語(yǔ)法規(guī)則,依次執(zhí)行。如果中間遇到大量復(fù)雜任務(wù),后面的代碼則會(huì)阻塞等待。
再來(lái)看一段異步代碼:
console.log('global begin')setTimeout(function timer1 () {console.log('timer1 invoke')}, 1800)setTimeout(function timer2 () {console.log('timer2 invoke')setTimeout(function inner () {console.log('inner invoke')}, 1000)}, 1000)console.log('global end')
異步代碼的執(zhí)行,要相對(duì)復(fù)雜一些。

代碼首先按照同步模式執(zhí)行,當(dāng)遇到異步代碼時(shí),會(huì)開(kāi)啟異步執(zhí)行線程。
在上面的代碼中,setTimeout 會(huì)開(kāi)啟環(huán)境運(yùn)行時(shí)的執(zhí)行線程運(yùn)行相關(guān)代碼。代碼運(yùn)行結(jié)束后,會(huì)將結(jié)果放入到消息隊(duì)列,等待 JS 線程結(jié)束后,消息隊(duì)列的任務(wù)再依次執(zhí)行。
流程圖如下:

下篇,我們來(lái)聊聊回調(diào)函數(shù)和異步方案。
周一見(jiàn)(? ?_?)?。
推薦閱讀:
技術(shù)人年度總結(jié) | 2020,注定不平凡
2020 最后一篇技術(shù)文:可愛(ài)的烏咪 UmiJS
前端人因?yàn)?Vue3 的 Ref-sugar 提案打起來(lái)了!
點(diǎn)點(diǎn)“贊”和“在看”,保護(hù)頭發(fā),減少bug。
