
文章插圖
筆者以前面試的時(shí)候經(jīng)常遇到寫一堆setTimeout,setImmediate來問哪個(gè)先執(zhí)行 。本文主要就是來講這個(gè)問題的,但是不是簡單的講講哪個(gè)先,哪個(gè)后 ?;\統(tǒng)的知道setImmediate比setTimeout(fn, 0)先執(zhí)行是不夠的,因?yàn)橛行┣闆r下setTimeout(fn, 0)是會(huì)比setImmediate先執(zhí)行的 。要徹底搞明白這個(gè)問題,我們需要系統(tǒng)的學(xué)習(xí)JS的異步機(jī)制和底層原理 。本文就會(huì)從異步基本概念出發(fā),一直講到Event Loop的底層原理,讓你徹底搞懂setTimeout,setImmediate,Promise, process.nextTick誰先誰后這一類問題 。
同步和異步同步異步簡單理解就是,同步的代碼都是按照書寫順序執(zhí)行的,異步的代碼可能跟書寫順序不一樣,寫在后面的可能先執(zhí)行 。下面來看個(gè)例子:
const syncFunc = () => {const time = new Date().getTime();while(true) {if(new Date().getTime() - time > 2000) {break;}}console.log(2);}console.log(1);syncFunc();console.log(3);上述代碼會(huì)先打印出1,然后調(diào)用syncFunc,syncFunc里面while循環(huán)會(huì)運(yùn)行2秒,然后打印出2,最后打印出3 。所以這里代碼的執(zhí)行順序跟我們的書寫順序是一致,他是同步代碼:
再來看個(gè)異步例子:
const asyncFunc = () => {setTimeout(() => {console.log(2);}, 2000);}console.log(1);asyncFunc();console.log(3);上述代碼的輸出是:
可以看到我們中間調(diào)用的asyncFunc里面的2卻是最后輸出的,這是因?yàn)閟etTimeout是一個(gè)異步方法 。他的作用是設(shè)置一個(gè)定時(shí)器,等定時(shí)器時(shí)間到了再執(zhí)行回調(diào)里面的代碼 。所以異步就相當(dāng)于做一件事,但是并不是馬上做,而是你先給別人打了個(gè)招呼,說xxx條件滿足的時(shí)候就干什么什么 。就像你晚上睡覺前在手機(jī)上設(shè)置了一個(gè)第二天早上7天的鬧鐘,就相當(dāng)于給了手機(jī)一個(gè)異步事件,觸發(fā)條件是時(shí)間到達(dá)早上7點(diǎn) 。使用異步的好處是你只需要設(shè)置好異步的觸發(fā)條件就可以去干別的事情了,所以異步不會(huì)阻塞主干上事件的執(zhí)行 。特別是對(duì)于JS這種只有一個(gè)線程的語言,如果都像我們第一個(gè)例子那樣去while(true),那瀏覽器就只有一直卡死了,只有等這個(gè)循環(huán)運(yùn)行完才會(huì)有響應(yīng) 。
JS異步是怎么實(shí)現(xiàn)的我們都知道JS是單線程的,那單線程是怎么實(shí)現(xiàn)異步的呢?事實(shí)上所謂的”JS是單線程的”只是指JS的主運(yùn)行線程只有一個(gè),而不是整個(gè)運(yùn)行環(huán)境都是單線程 。JS的運(yùn)行環(huán)境主要是瀏覽器,以大家都很熟悉的Chrome的內(nèi)核為例,他不僅是多線程的,而且是多進(jìn)程的:
上圖只是一個(gè)概括分類,意思是Chrome有這幾類的進(jìn)程和線程,并不是每種只有一個(gè),比如渲染進(jìn)程就有多個(gè),每個(gè)選項(xiàng)卡都有自己的渲染進(jìn)程 。有時(shí)候我們使用Chrome會(huì)遇到某個(gè)選項(xiàng)卡崩潰或者沒有響應(yīng)的情況,這個(gè)選項(xiàng)卡對(duì)應(yīng)的渲染進(jìn)程可能就崩潰了,但是其他選項(xiàng)卡并沒有用這個(gè)渲染進(jìn)程,他們有自己的渲染進(jìn)程,所以其他選項(xiàng)卡并不會(huì)受影響 。這也是Chrome單個(gè)頁面崩潰并不會(huì)導(dǎo)致瀏覽器崩潰的原因,而不是像老IE那樣,一個(gè)頁面卡了導(dǎo)致整個(gè)瀏覽器都卡 。
對(duì)于前端工程師來說,主要關(guān)心的還是渲染進(jìn)程,下面來分別看下里面每個(gè)線程是做什么的 。
GUI線程GUI線程就是渲染頁面的,他解析HTML和CSS,然后將他們構(gòu)建成DOM樹和渲染樹就是這個(gè)線程負(fù)責(zé)的 。
JS引擎線程這個(gè)線程就是負(fù)責(zé)執(zhí)行JS的主線程,前面說的”JS是單線程的”就是指的這個(gè)線程 。大名鼎鼎的Chrome V8引擎就是在這個(gè)線程運(yùn)行的 。需要注意的是,這個(gè)線程跟GUI線程是互斥的 ?;コ獾脑蚴荍S也可以操作DOM,如果JS線程和GUI線程同時(shí)操作DOM,結(jié)果就混亂了,不知道到底渲染哪個(gè)結(jié)果 。這帶來的后果就是如果JS長時(shí)間運(yùn)行,GUI線程就不能執(zhí)行,整個(gè)頁面就感覺卡死了 。所以我們最開始例子的while(true)這樣長時(shí)間的同步代碼在真正開發(fā)時(shí)是絕對(duì)不允許的 。
以上關(guān)于本文的內(nèi)容,僅作參考!溫馨提示:如遇健康、疾病相關(guān)的問題,請(qǐng)您及時(shí)就醫(yī)或請(qǐng)專業(yè)人士給予相關(guān)指導(dǎo)!
「愛刨根生活網(wǎng)」www.malaban59.cn小編還為您精選了以下內(nèi)容,希望對(duì)您有所幫助:- 工廠平面圖制作方法 工廠平面設(shè)計(jì)圖的步驟
- json數(shù)據(jù)自動(dòng)生成表格方法 json轉(zhuǎn)excel表格工具
- 申請(qǐng)英國讀大學(xué)的誤區(qū)有哪些
- 米生小黑蟲怎么辦啊
- 牙膏的保質(zhì)期一般多久
- 類似機(jī)車的電動(dòng)車 適合青少年騎的電動(dòng)車
- 佛手瓜的皮能吃嗎
- 五花肉腌制方法燒烤
- 抖音文案視頻素材,抖音短視頻的文案怎樣寫
- 牛板筋是牛的哪個(gè)部位
