首先要糾正一個(gè)誤區(qū):JS其實(shí)就是一門語(yǔ)言,說(shuō)是單線程還是多線程得結(jié)合具體運(yùn)行環(huán)境(瀏覽器)。
瀏覽器的內(nèi)核是多線程的。
一個(gè)瀏覽器通常由以下幾個(gè)常駐的線程:
渲染引擎線程:顧名思義,該線程負(fù)責(zé)頁(yè)面的渲染
JS引擎線程:負(fù)責(zé)JS的解析和執(zhí)行
定時(shí)觸發(fā)器線程:處理定時(shí)事件,比如setTimeout, setInterval
事件觸發(fā)線程:處理DOM事件
異步http請(qǐng)求線程:處理http請(qǐng)求
JS引擎
負(fù)責(zé)JS代碼的解析和執(zhí)行(注意是瀏覽器自己開(kāi)了一個(gè)線程)。通常包括以下幾個(gè)步驟:
詞法分析:將源代碼分解為有意義的分詞
語(yǔ)法分析:用語(yǔ)法分析器將分詞解析成語(yǔ)法樹(shù)
代碼生成:生成可執(zhí)行代碼(將所有JS代碼全部生成為可執(zhí)行代碼)
函數(shù)調(diào)用棧的更新:遵循代碼順序,不同上下文出入函數(shù)調(diào)用棧。伴隨函數(shù)調(diào)用棧的更新,JS代碼逐句執(zhí)行至尾部。
瀏覽器在運(yùn)行時(shí)只開(kāi)啟了一個(gè)JS引擎線程來(lái)解析和執(zhí)行JS。且要記得無(wú)論是同步還是異步執(zhí)行,JS引擎線程的運(yùn)行始終是非阻塞的,這是在設(shè)計(jì)之初就定下的。
JS異步執(zhí)行
JS引擎的事件循環(huán)機(jī)制是JS實(shí)現(xiàn)異步執(zhí)行的前提。在上下文的不斷切換,函數(shù)調(diào)用棧的更新過(guò)程中,一旦發(fā)現(xiàn)"事件綁定,AJAX,setTimeout/setInterval"等任務(wù),會(huì)把它們會(huì)將其放入消息隊(duì)列中。當(dāng)函數(shù)調(diào)用棧為空時(shí),JS引擎會(huì)執(zhí)行一次循環(huán),將事件隊(duì)列的隊(duì)首出隊(duì)至函數(shù)調(diào)用棧中。
待續(xù)