Js既然是單線程的仪壮,怎么會有異步這種操作呢憨颠!

前言
說到j(luò)s的單線程(single threaded)和異步(asynchronous),很多同學(xué)不禁會想积锅,這不是自相矛盾么爽彤?其實(shí),單線程和異步確實(shí)不能同時成為一個語言的特性缚陷。js選擇了成為單線程的語言适篙,所以它本身不可能是異步的,但js的宿主環(huán)境(比如瀏覽器箫爷,Node)是多線程的嚷节,宿主環(huán)境通過某種方式(事件驅(qū)動聂儒,下文會講)使得js具備了異步的屬性。往下看硫痰,你會發(fā)現(xiàn)js的機(jī)制是多么的簡單高效衩婚!

說說瀏覽器

js是單線程語言,瀏覽器只分配給js一個主線程碍论,用來執(zhí)行任務(wù)(函數(shù))谅猾,但一次只能執(zhí)行一個任務(wù),這些任務(wù)形成一個任務(wù)隊(duì)列排隊(duì)等候執(zhí)行鳍悠,但前端的某些任務(wù)是非常耗時的税娜,比如網(wǎng)絡(luò)請求,定時器和事件監(jiān)聽藏研,如果讓他們和別的任務(wù)一樣敬矩,都老老實(shí)實(shí)的排隊(duì)等待執(zhí)行的話,執(zhí)行效率會非常的低蠢挡,甚至導(dǎo)致頁面的假死弧岳。所以,瀏覽器為這些耗時任務(wù)開辟了另外的線程业踏,主要包括http請求線程禽炬,瀏覽器定時觸發(fā)器,瀏覽器事件觸發(fā)線程勤家,這些任務(wù)是異步的腹尖。下圖說明了瀏覽器的主要線程。

image.png

再說說任務(wù)隊(duì)列

剛才說到瀏覽器為網(wǎng)絡(luò)請求這樣的異步任務(wù)單獨(dú)開了一個線程伐脖,那么問題來了热幔,這些異步任務(wù)完成后,主線程怎么知道呢讼庇?答案就是回調(diào)函數(shù)绎巨,整個程序是事件驅(qū)動的,每個事件都會綁定相應(yīng)的回調(diào)函數(shù)蠕啄,舉個栗子场勤,有段代碼設(shè)置了一個定時器setTimeout(function(){ console.log(time is out);},50);

執(zhí)行這段代碼的時候歼跟,瀏覽器異步執(zhí)行計時操作和媳,當(dāng)50ms到了后,會觸發(fā)定時事件嘹承,這個時候窗价,就會把回調(diào)函數(shù)放到任務(wù)隊(duì)列里。整個程序就是通過這樣的一個個事件驅(qū)動起來的叹卷。

所以說撼港,js是一直是單線程的坪它,瀏覽器才是實(shí)現(xiàn)異步的那個家伙。

說回主線程

js一直在做一個工作帝牡,就是從任務(wù)隊(duì)列里提取任務(wù)往毡,放到主線程里執(zhí)行。下面我們來進(jìn)行更深一步的理解靶溜。


image.png

我們把剛才了解的概念和圖中做一個對應(yīng)开瞭,上文中說到的瀏覽器為異步任務(wù)單獨(dú)開辟的線程可以統(tǒng)一理解為WebAPIs,上文中說到的任務(wù)隊(duì)列就是callback queue罩息,我們所說的主線程就是有虛線組成的那一部分嗤详,堆(heap)和棧(stack)共同組成了js主線程,函數(shù)的執(zhí)行就是通過進(jìn)棧和出棧實(shí)現(xiàn)的瓷炮,比如圖中有一個foo()函數(shù)葱色,主線程把它推入棧中,在執(zhí)行函數(shù)體時娘香,發(fā)現(xiàn)還需要執(zhí)行上面的那幾個函數(shù)苍狰,所以又把這幾個函數(shù)推入棧中,等到函數(shù)執(zhí)行完烘绽,就讓函數(shù)出棧淋昭。等到stack清空時,說明一個任務(wù)已經(jīng)執(zhí)行完了安接,這時就會從callback queue中尋找下一個人任務(wù)推入棧中(這個尋找的過程翔忽,叫做event loop英古,因?yàn)樗偸茄h(huán)的查找任務(wù)隊(duì)列里是否還有任務(wù))妆兑。

借以解釋幾個容易困惑的問題

setTimeout(f1,0)是什么鬼

這個語句最大的疑問是,f1是不是立刻執(zhí)行?答案是不一定糯笙,因?yàn)橐粗骶€程內(nèi)的命令是否已經(jīng)執(zhí)行完了,如下代碼:setTimeout(function(){console.log(1);},0);console.log(2);

這段代碼的輸出結(jié)果是2,1撩银。因?yàn)閳?zhí)行setTimeou后给涕,會立即把匿名函數(shù)放到callback queue里面等待主線程的召喚,但這個時候stack里面并不是空的额获,因?yàn)檫€有一句console.log(2)够庙。等到執(zhí)行完console.log(2)后,才通過event loop把匿名函數(shù)放到stack里面抄邀。所以setTimeout(f1,0)這個語句并不是沒有意義耘眨,如果f1是很耗時的任務(wù),那就應(yīng)該把任務(wù)放到callback queue里面境肾,等到主程序執(zhí)行完后再執(zhí)行剔难。

了解完上文內(nèi)容胆屿,我們就知道了,ajax請求內(nèi)容的時候是異步的偶宫,當(dāng)請求完成后非迹,會觸發(fā)請求完成的事件,然后把回調(diào)函數(shù)放入callback queue纯趋,等到主線程執(zhí)行該回調(diào)函數(shù)時還是單線程的憎兽。
界面渲染線程是單獨(dú)開辟的線程,是不是DOM一變化吵冒,界面就立刻重新渲染纯命?如果DOM一變化,界面就立刻重新渲染痹栖,效率必然很低扎附,所以瀏覽器的機(jī)制規(guī)定界面渲染線程和主線程是互斥的,主線程執(zhí)行任務(wù)時结耀,瀏覽器渲染線程處于掛起狀態(tài)留夜。

如何利用瀏覽器的異步機(jī)制

我們已經(jīng)知道,js一直是單線程執(zhí)行的图甜,瀏覽器為幾個明顯的耗時任務(wù)單獨(dú)開辟線程解決耗時問題碍粥,但是js除了這幾個明顯的耗時問題外,可能我們自己寫的程序里面也會有耗時的函數(shù)黑毅,這種情況怎么處理呢嚼摩?我們肯定不能自己開辟單獨(dú)的線程,但我們可以利用瀏覽器給我們開放的這幾個矿瘦,瀏覽器定時器線程和事件觸發(fā)線程是好利用的枕面,網(wǎng)絡(luò)請求線程不適合我們使用。

異步的好處和適合的場景

1.異步的好處

我們直接通過一個例子對同步和異步進(jìn)行對比缚去,假設(shè)有四個任務(wù)(編號為1,2,3,4)潮秘,它們的執(zhí)行時間都是10ms,其中任務(wù)2是任務(wù)3的前置任務(wù),任務(wù)2需要20ms的響應(yīng)時間易结。下面我們做下對比枕荞,你就知道怎么實(shí)現(xiàn)的非阻塞I/O了。


image.png

2.適合的場景

可以看出搞动,當(dāng)我們的程序需要大量I/O操作和用戶請求時躏精,js這個具備單線程,異步鹦肿,事件驅(qū)動多種氣質(zhì)的語言是多么應(yīng)景矗烛!相比于多線程語言,它不必耗費(fèi)過多的系統(tǒng)開銷箩溃,同時也不必把精力用于處理多線程管理瞭吃,相比于同步執(zhí)行的語言碌识,宿主環(huán)境的異步和事件驅(qū)動機(jī)制又讓它實(shí)現(xiàn)了非阻塞I/O,所以你應(yīng)該知道它適合什么樣的場景了吧虱而!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末筏餐,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子牡拇,更是在濱河造成了極大的恐慌魁瞪,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件惠呼,死亡現(xiàn)場離奇詭異导俘,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)剔蹋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門旅薄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人泣崩,你說我怎么就攤上這事少梁。” “怎么了矫付?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵凯沪,是天一觀的道長。 經(jīng)常有香客問我买优,道長妨马,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任杀赢,我火速辦了婚禮烘跺,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘脂崔。我一直安慰自己滤淳,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布脱篙。 她就那樣靜靜地躺著娇钱,像睡著了一般伤柄。 火紅的嫁衣襯著肌膚如雪绊困。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天适刀,我揣著相機(jī)與錄音秤朗,去河邊找鬼。 笑死笔喉,一個胖子當(dāng)著我的面吹牛取视,可吹牛的內(nèi)容都是我干的硝皂。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼作谭,長吁一口氣:“原來是場噩夢啊……” “哼稽物!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起折欠,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤贝或,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后锐秦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體咪奖,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年酱床,在試婚紗的時候發(fā)現(xiàn)自己被綠了羊赵。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡扇谣,死狀恐怖昧捷,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情罐寨,我是刑警寧澤料身,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站衩茸,受9級特大地震影響芹血,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜楞慈,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一幔烛、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧囊蓝,春花似錦饿悬、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蝎宇,卻和暖如春弟劲,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背姥芥。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工兔乞, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓庸追,卻偏偏與公主長得像霍骄,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子淡溯,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容