javaScript是典型的單線程并發(fā)語言藕漱,表示在同一時(shí)間內(nèi)只能執(zhí)行單個(gè)任務(wù)或部分代碼片,它的主要用途是與用戶互動(dòng)景醇,以及操作DOM臀稚,這就決定了它只能是個(gè)單線程。即javaScript主線程擁有一個(gè)函數(shù)調(diào)用棧以及一個(gè)任務(wù)隊(duì)列三痰。主線程依次執(zhí)行代碼吧寺,遇到函數(shù)時(shí),會(huì)先將函數(shù)入棧散劫,函數(shù)運(yùn)行完畢后再將函數(shù)出棧稚机,直到所有代碼執(zhí)行完畢。當(dāng)函數(shù)調(diào)用棧為空時(shí)获搏,運(yùn)行時(shí)根據(jù)事件循環(huán)(EventLoop)機(jī)制來從任務(wù)隊(duì)列中取出待執(zhí)行的回調(diào)并執(zhí)行赖条,執(zhí)行過程中同樣會(huì)進(jìn)行函數(shù)幀的入棧出棧操作。
H5中的Web Worker標(biāo)準(zhǔn)雖然是多線程,但Web Worker和JS主線程不是平級的谋币,主線程可以控制Web Worker,并且Web Worker不能操作DOM症概,不能訪問document蕾额、window、parent彼城。
JavaScript中的其它線程诅蝶,定時(shí)觸發(fā)線程,異步請求線程募壕,處理DOM事件的線程调炬,稱之為工作線程。
Event Loop(事件循環(huán))并不是 JavaScript 中獨(dú)有的舱馅,其廣泛應(yīng)用于各個(gè)領(lǐng)域的異步編程實(shí)現(xiàn)中缰泡;所謂的 Event Loop 即是一系列回調(diào)函數(shù)的集合,在執(zhí)行某個(gè)異步函數(shù)時(shí)代嗤,會(huì)將其回調(diào)壓入隊(duì)列中棘钞,JavaScript 引擎會(huì)在異步代碼執(zhí)行完畢后開始處理其關(guān)聯(lián)的回調(diào)。
在 Web 瀏覽器中干毅,任何時(shí)刻都有可能會(huì)有事件被觸發(fā)宜猜,而僅有那些設(shè)置了回調(diào)的事件會(huì)將其相關(guān)的任務(wù)壓入到任務(wù)隊(duì)列中
任務(wù)隊(duì)列是一個(gè)事件的隊(duì)列,也可以理解成消息的隊(duì)列硝逢。
所有同步任務(wù)都在主線程上執(zhí)行姨拥,形成一個(gè)執(zhí)行棧。
只要異步任務(wù)有了運(yùn)行結(jié)果渠鸽,就在"任務(wù)隊(duì)列"之中放置一個(gè)事件叫乌。
瀏覽器中的事件循環(huán)機(jī)制闡述如下:
1.瀏覽器內(nèi)核會(huì)在其它線程中執(zhí)行異步操作,當(dāng)操作完成后徽缚,將操作結(jié)果以及事先定義的回調(diào)函數(shù)放入 JavaScript 主線程的任務(wù)隊(duì)列中综芥。
2.JavaScript 主線程會(huì)在執(zhí)行棧清空后,讀取任務(wù)隊(duì)列猎拨,讀取到任務(wù)隊(duì)列中的函數(shù)后膀藐,將該函數(shù)入棧,一直運(yùn)行直到執(zhí)行棧清空红省,再次去讀取任務(wù)隊(duì)列额各,不斷循環(huán)。
3.當(dāng)主線程阻塞時(shí)吧恃,任務(wù)隊(duì)列仍然是能夠被推入任務(wù)的虾啦。這也就是為什么當(dāng)頁面的 JavaScript 進(jìn)程阻塞時(shí),我們觸發(fā)的點(diǎn)擊等事件,會(huì)在進(jìn)程恢復(fù)后依次執(zhí)行傲醉。
JavaScript 內(nèi)存模型的角度蝇闭,我們可以將內(nèi)存劃分為調(diào)用棧(Call Stack)、堆(Heap)以及隊(duì)列(Queue)等幾個(gè)部分硬毕。