? ? ? ? 各位看官我們又見(jiàn)面了恭金,這幾天剛和媳婦拍完結(jié)婚照回來(lái)了项贺,曬得跟非洲的猴子一樣~
? ? ? ? 總算有點(diǎn)時(shí)間了,打算再寫(xiě)一篇博文寇蚊,來(lái)掃一下我之前對(duì)異步隊(duì)列的盲點(diǎn)笔时,同時(shí)論證一下異步更新在Dom優(yōu)化時(shí)所起到的作用。
? ? ? ? 從前仗岸,在我的認(rèn)知里允耿,js這個(gè)單線程的語(yǔ)言如果想做異步操作(ajax,setTimeout扒怖,onclick)的話较锡,就需要將所有的異步事件安排到一組事件隊(duì)列中去,當(dāng)主線程的代碼全部跑完盗痒,再?gòu)年?duì)列中的去一個(gè)個(gè)執(zhí)行異步事件蚂蕴。我覺(jué)得與其叫做異步,倒不如叫它事件補(bǔ)充精準(zhǔn)吧~
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? —— 高級(jí)裝B工程師 Yubble
? ? ? ? 以上的結(jié)論還是沒(méi)有問(wèn)題的,不管去哪面試對(duì)方一問(wèn)到異步只要回答出上面這一段話效果就都是ok的(來(lái)自在下面試各大一線互聯(lián)網(wǎng)公司的親身經(jīng)歷骡楼,嗚嗚嗚~)
? ? ? ? 但是熔号!我們是脫離了低級(jí)趣味的人,我是提倡裝就要裝出高逼格的人鸟整,如果客爺您能滔滔不絕的說(shuō)出異步隊(duì)列中包含的兩種隊(duì)列:macro (宏任務(wù)隊(duì)列) 和 micro (微任務(wù)隊(duì)列)引镊,那您很有可能成為面試官欽點(diǎn)的Mr.Right了,
? ? ? ? 大風(fēng)起兮云飛揚(yáng)~道是無(wú)晴卻有晴
? ? ? ? 首先看看這兩種異步事件的成員吧
? ? ? ? 常見(jiàn)的Micro-Task事件:process.nextTick(nodeJs)吃嘿、Promise祠乃、MutationObserver 等。
? ? ? ? 常見(jiàn)的Macro-Task事件:setTimeout兑燥、setInterval亮瓷、 setImmediate(nodeJs)、script(整體代碼)
? ? ? ? 有沒(méi)有覺(jué)得Macro-Task的事件都眼熟降瞳,Micro-Task的事件都臉兒生嘱支,也就是說(shuō)在Promise,MutationObserver這些h5新特性問(wèn)世之前挣饥,異步隊(duì)列一直都是Macro-Task一家說(shuō)了算除师,就是我們以前說(shuō)的任務(wù)隊(duì)列(task queue)!
? ? ? ? 那么問(wèn)題來(lái)了扔枫,這哥兒倆都是異步事件汛聚,在一次事件循環(huán)的過(guò)程中誰(shuí)先誰(shuí)后呢?首先我們來(lái)看一張Event Loop的周期示例圖:
? ? ? ? 是不是剛一看有點(diǎn)懵短荐,在下剛開(kāi)始看到這張圖的時(shí)候是這樣的
? ? ? ? 先不要輕易放棄哦我的小可愛(ài)們倚舀,我們先簡(jiǎn)單的歸納一下這一次事件循環(huán)的周期都做了什么。
? ? ? ? 1忍宋,首先瀏覽器將macro隊(duì)列中的 一個(gè)任務(wù) 單獨(dú)出列執(zhí)行了痕貌,是一個(gè)任務(wù)哦
? ? ? ? 2,執(zhí)行完畢后緊接著micro隊(duì)列拋出 所有任務(wù) 依次執(zhí)行糠排,是所有micro任務(wù)哦
? ? ? ? 3舵稠,到了這個(gè)節(jié)點(diǎn),如果異步函數(shù)中有對(duì)于dom的操作入宦,便可以執(zhí)行了哺徊,dom變化了就會(huì)引起瀏覽器的回流與重繪
? ? ? ? 4,將worker線程中的任務(wù)釋放執(zhí)行出來(lái)云石,這里就不多說(shuō)了~
? ? ? ? 他們的區(qū)別是很明顯的對(duì)嗎唉工?在每一次的事件循環(huán)中macro的事件隊(duì)列是一個(gè)個(gè)的執(zhí)行的,然而每執(zhí)行完一個(gè)macro事件都會(huì)將所有的micro事件一同執(zhí)行汹忠,緊接著立即去做dom的變化~
? ? ? ? 我們來(lái)簡(jiǎn)單的做一個(gè)驗(yàn)證喉淋硝,我將macro異步的代表 setTimeout 與micro異步的代表 promise 穿插著寫(xiě)在一起
? ? ? ? 這里也就不賣關(guān)子了雹熬,正確的輸出是
? ? ? ? 一目了然,不論我們將同一域中的macro和micro以什么順序編寫(xiě)谣膳,micro的執(zhí)行順序都會(huì)在macro之前竿报,并且是將所有的micro事件一起出隊(duì)。
? ? ? ? 這位客爺問(wèn)了继谚,“上面不是說(shuō)先執(zhí)行macro的事件烈菌,再執(zhí)行micro事件嗎,你這個(gè)怎么micro比macro要優(yōu)先吶花履?”芽世,特別好,您能看到這里我很有成就感诡壁,這是因?yàn)?b>script標(biāo)簽本就在macro隊(duì)列之中济瓢!下面在下就用我平時(shí)最通俗的大碴子話來(lái)給各位看官敘述一下這幾行代碼在瀏覽器運(yùn)行時(shí)的過(guò)程:
? ? ? ? 1, 瀏覽器運(yùn)行到<script>的狀態(tài):調(diào)用椕们洌空旺矾。micro隊(duì)列為空,macro隊(duì)列中只有一個(gè)script腳本(包含script的全部?jī)?nèi)容)
? ? ? ? 2夺克,<script>的代碼開(kāi)始執(zhí)行箕宙,在執(zhí)行script代碼中內(nèi)容的時(shí)候,將所有的異步代碼分成了macro與micro铺纽,并分別進(jìn)入隊(duì)列柬帕。等待同步代碼全部執(zhí)行完成
? ? ? ? 3,檢測(cè)到macro隊(duì)列中有事件在排隊(duì)狡门,第一個(gè)等待出隊(duì)的是<script>雕崩。注意了,此時(shí)是script從macro出隊(duì)了融撞。
? ? ? ? 4,執(zhí)行完一個(gè)macro任務(wù)粗蔚,就該將整隊(duì)的micro任務(wù)出隊(duì)執(zhí)行了吧尝偎,于是乎在同步代碼執(zhí)行時(shí)被寫(xiě)入micro隊(duì)列中的所有Promise就一窩蜂的跑了出來(lái)。
? ? ? ? 5鹏控,之后開(kāi)始進(jìn)行異步回調(diào)中的dom操作致扯,觸發(fā)瀏覽器渲染,執(zhí)行worker当辐,完成一個(gè)閉環(huán)抖僵。緊接著執(zhí)行下一個(gè)macro異步事件(setTimeout)
? ? ? ? 所以我們能夠清楚的是,macro隊(duì)列中有多少異步事件缘揪,我們的瀏覽器就要走多少次的3耍群,4义桂,5。
? ? ? ? 結(jié)論:
? ? ? ? ? ? ? ? 經(jīng)過(guò)了一番折騰我想各位客爺也明白我想表達(dá)的意思了蹈垢,如果我們想要在同步代碼執(zhí)行完成之后用異步的方式來(lái)更新dom慷吊,盡量要寫(xiě)在micro的異步事件中去,他是可以第一時(shí)間將dom變化觸發(fā)渲染的曹抬,你來(lái)了嗎田利小哥溉瓶,不要再把異步更新dom寫(xiě)到setTimeout上去啦。
? ? ? ? ? ? ? ? 如果各位客爺使用過(guò)vue的nextTick的話谤民,不妨看一看它的源碼堰酿,在異步更新dom上,它就是這么優(yōu)化的张足,上圖~
? ? ? ? ? ? ? ? 閑聊幾句吧触创,最近我的第一個(gè)小程序正在做備案,馬上就要上線啦兢榨,打算用這個(gè)跟我女朋友求婚一舉拿下嗅榕,哈哈,來(lái)自程序員的浪漫~
? ? ? ? ? ? ? ? 最后祝各位新年快樂(lè)吵聪,來(lái)年發(fā)大財(cái)凌那,家家大豐收