首先,js是單線(xiàn)程的,這一點(diǎn)毋庸置疑。
同步異步的概念:
同步:大家按照順序,你運(yùn)行完我運(yùn)行,不存在你我同時(shí)運(yùn)行的情況;優(yōu)點(diǎn)是實(shí)現(xiàn)起來(lái)比較簡(jiǎn)單,執(zhí)行環(huán)境相對(duì)單純;壞處是一旦出現(xiàn)耗時(shí)操作就會(huì)導(dǎo)致整個(gè)程序癱瘓,停止運(yùn)行;
異步:大家齊頭并進(jìn),一起運(yùn)行,也就是明面上的“多線(xiàn)程”;
既然異步就約等于多線(xiàn)程,那js這樣一個(gè)單線(xiàn)程語(yǔ)言中,怎么會(huì)存在異步呢?其實(shí)實(shí)際上js確實(shí)不存在真正意義上的“異步”,而是使用 events loop 來(lái)實(shí)現(xiàn)類(lèi)似異步的效果。events loop 實(shí)際上就是在js在主要代碼(也就是在html中所有定義的script標(biāo)簽)運(yùn)行完后,會(huì)開(kāi)啟的一個(gè)循環(huán),主要用于監(jiān)聽(tīng) HTML 事件和執(zhí)行異步操作。所以實(shí)際上js就是單線(xiàn)程的,包括setTimeout,setInterval,XMLHttpRequest都是如此的操作:將需要執(zhí)行的耗時(shí)操作放入循環(huán)中,并在恰當(dāng)實(shí)際執(zhí)行回調(diào)函數(shù)。
我們可以用以下代碼來(lái)測(cè)試js一定是單線(xiàn)程:
setTImeout(function(){
alert("我是一個(gè)彈窗");
},1000);
while(true){
//不會(huì)結(jié)束的死循環(huán)
}
js有多種方法來(lái)實(shí)現(xiàn)偽異步,比如:回調(diào)函數(shù),事件監(jiān)聽(tīng),發(fā)布訂閱,Promises對(duì)象。
回調(diào)函數(shù)就是上述的setTimeout,setInterval,XMLHttpRequest所使用的方法,傳入一個(gè)函數(shù),并在耗時(shí)操作完成時(shí)執(zhí)行。
事件監(jiān)聽(tīng)就是設(shè)定幾個(gè)事件,為其設(shè)置監(jiān)聽(tīng)事件,當(dāng)某個(gè)事件發(fā)生時(shí),執(zhí)行對(duì)應(yīng)的函數(shù)。
發(fā)布訂閱這個(gè)模式與安卓中的廣播類(lèi)似,可以通過(guò)一個(gè)“平臺(tái)”來(lái)“發(fā)布”某些信息,之后會(huì)將這個(gè)調(diào)用所有“訂閱”這個(gè)信息的函數(shù),與事件監(jiān)聽(tīng)很像,但是可以通過(guò)從消息中心(其實(shí)就是)查看來(lái)更好的監(jiān)控程序。
Promises函數(shù),每一個(gè)異步任務(wù)返回一個(gè)Promise對(duì)象,該對(duì)象有一個(gè)then方法,允許指定回調(diào)函數(shù),會(huì)在上一個(gè)世界結(jié)束后調(diào)用。(詳細(xì)可以查看菜鳥(niǎo)教程等)
其實(shí)看完你會(huì)發(fā)現(xiàn),所有在js中的“異步”操作,都是耗時(shí)操作加入事件循環(huán),并在特定時(shí)機(jī)執(zhí)行一個(gè)函數(shù)的模式。
原文鏈接