js是單線程為什么可以進行異步操作默赂?

(1) JS是單線程語言

(2) JS的Event Loop是JS的執(zhí)行機制。深入了解JS的執(zhí)行,就等于深入了解JS里的event loop。

1. JS為什么是單線程的? 為什么需要異步? 單線程又是如何實現(xiàn)異步的呢?

問題1:JS為什么是單線程的?

? ? ?JS最初被設(shè)計用在瀏覽器中,那么想象一下,如果瀏覽器中的JS是多線程的田藐。

那么現(xiàn)在有2個進程,process1?process2,由于是多進程的JS,所以他們對同一個dom,同時進行操作

process1?刪除了該dom,而process2?編輯了該dom,同時下達2個矛盾的命令,瀏覽器究竟該如何執(zhí)行呢?

問題2:JS為什么需要異步?

? ? ?如果JS中不存在異步,只能自上而下執(zhí)行,如果上一行解析時間很長,那么下面的代碼就會被阻塞。對于用戶而言,阻塞就意味著"卡死",這樣就導(dǎo)致了很差的用戶體驗吱七,所以,JS中存在異步執(zhí)行汽久。

問題3:JS單線程又是如何實現(xiàn)異步的呢?

既然JS是單線程的,只能在一條線程上執(zhí)行,又是如何實現(xiàn)的異步呢?

是通過的事件循環(huán)(event loop),理解了event loop機制,就理解了JS的執(zhí)行機制。

-------------------------------------------------------------------------------------------------------------------------------------------------

JS中的event loop(1)

例1,觀察它的執(zhí)行順序

console.log(1)

setTimeout(function(){

console.log(2)

},0)

console.log(3)

運行結(jié)果是: 1 3 2

也就是說,setTimeout里的函數(shù)并沒有立即執(zhí)行,而是延遲了一段時間,滿足一定條件后,才去執(zhí)行的,這類代碼,我們叫異步代碼踊餐。

所以,這里我們首先知道了JS里的一種分類方式,就是將任務(wù)分為: 同步任務(wù)和異步任務(wù)

圖片描述

按照這種分類方式:JS的執(zhí)行機制是

首先判斷JS是同步還是異步,同步就進入主進程,異步就進入event table

異步任務(wù)在event table中注冊函數(shù),當滿足觸發(fā)條件后,被推入event queue

同步任務(wù)進入主線程后一直執(zhí)行,直到主線程空閑時,才會去event queue中查看是否有可執(zhí)行的異步任務(wù),如果有就推入主進程中

以上三步循環(huán)執(zhí)行,這就是event loop景醇。

? ??console.log(1)?是同步任務(wù),放入主線程里

setTimeout()?是異步任務(wù),被放入event?table,?0秒之后被推入event?queue里

console.log(3 )是同步任務(wù),放到主線程里

當?1、?3在控制條被打印后,主線程去event?queue(事件隊列)里查看是否有可執(zhí)行的函數(shù),執(zhí)行setTimeout里的函數(shù)

------------------------------------------------------------------------------------------------------------------------------------------

JS中的event loop(2)

setTimeout(function(){

?console.log('定時器開始啦')

});

new?Promise(function(resolve){

?console.log('馬上執(zhí)行for循環(huán)啦');

?for(var?i?=?0;?i

嘗試按照,上文我們剛學(xué)到的JS執(zhí)行機制去分析

setTimeout?是異步任務(wù),被放到event?table

new?Promise?是同步任務(wù),被放到主進程里,直接執(zhí)行打印?console.log('馬上執(zhí)行for循環(huán)啦')

.then里的函數(shù)是?異步任務(wù),被放到event?table

console.log('代碼執(zhí)行結(jié)束')是同步代碼,被放到主進程里,直接執(zhí)行

---------------------------------------------------------------------------------------------------------------------

所以,結(jié)果是 【馬上執(zhí)行for循環(huán)啦 — 代碼執(zhí)行結(jié)束 — 定時器開始啦 — 執(zhí)行then函數(shù)啦】嗎?

親自執(zhí)行后,結(jié)果居然不是這樣,而是【馬上執(zhí)行for循環(huán)啦 — 代碼執(zhí)行結(jié)束 — 執(zhí)行then函數(shù)啦 — 定時器開始啦】

那么,難道是異步任務(wù)的執(zhí)行順序,不是前后順序,而是另有規(guī)定? 事實上,按照異步和同步的劃分方式,并不準確市袖。

而準確的劃分方式是:

macro-task(宏任務(wù)):包括整體代碼script啡直,setTimeout,setInterval

micro-task(微任務(wù)):Promise苍碟,process.nextTick.

按照這種分類方式:JS的執(zhí)行機制是:

執(zhí)行一個宏任務(wù),過程中如果遇到微任務(wù),就將其放到微任務(wù)的【事件隊列】里

當前宏任務(wù)執(zhí)行完成后,會查看微任務(wù)的【事件隊列】,并將里面全部的微任務(wù)依次執(zhí)行完

重復(fù)以上2步驟,結(jié)合event loop(1) event loop(2) ,就是更為準確的JS執(zhí)行機制了酒觅。

---------------------------------------------------------------------------------------------------------------------

首先執(zhí)行script下的宏任務(wù),遇到setTimeout,將其放到宏任務(wù)的【隊列】里

遇到?new?Promise直接執(zhí)行,打印"馬上執(zhí)行for循環(huán)啦"

遇到then方法,是微任務(wù),將其放到微任務(wù)的【隊列里】

打印?"代碼執(zhí)行結(jié)束"

本輪宏任務(wù)執(zhí)行完畢,查看本輪的微任務(wù),發(fā)現(xiàn)有一個then方法里的函數(shù),?打印"執(zhí)行then函數(shù)啦"

到此,本輪的event?loop?全部完成。下一輪的循環(huán)里,先執(zhí)行一個宏任務(wù),發(fā)現(xiàn)宏任務(wù)的【隊列】里有一個?setTimeout里的函數(shù),執(zhí)行打印"定時器開始啦"

所以最后的執(zhí)行順序是【馬上執(zhí)行for循環(huán)啦 — 代碼執(zhí)行結(jié)束 — 執(zhí)行then函數(shù)啦 — 定時器開始啦】

-------------------------------------------------------------------------------------------------------------------------------------

?談?wù)剆etTimeout

這段setTimeout代碼什么意思? 我們一般說: 3秒后,會執(zhí)行setTimeout里的那個函數(shù)

setTimeout(function(){

console.log('執(zhí)行了')

},3000)

但是這種說并不嚴謹,準確的解釋是: 3秒后,setTimeout里的函數(shù)被會推入event queue,而event queue(事件隊列)里的任務(wù),只有在主線程空閑時才會執(zhí)行微峰。

所以只有滿足 (1)3秒后 (2)主線程空閑,同時滿足時,才會3秒后執(zhí)行該函數(shù)

如果主線程執(zhí)行內(nèi)容很多,執(zhí)行時間超過3秒,比如執(zhí)行了10秒,那么這個函數(shù)只能10秒后執(zhí)行了

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末舷丹,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子蜓肆,更是在濱河造成了極大的恐慌颜凯,老刑警劉巖谋币,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異症概,居然都是意外死亡蕾额,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進店門彼城,熙熙樓的掌柜王于貴愁眉苦臉地迎上來诅蝶,“玉大人,你說我怎么就攤上這事募壕〉骶妫” “怎么了?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵舱馅,是天一觀的道長缰泡。 經(jīng)常有香客問我,道長代嗤,這世上最難降的妖魔是什么棘钞? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮资溃,結(jié)果婚禮上武翎,老公的妹妹穿的比我還像新娘。我一直安慰自己溶锭,他們只是感情好宝恶,可當我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著趴捅,像睡著了一般垫毙。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上拱绑,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天综芥,我揣著相機與錄音负乡,去河邊找鬼延塑。 笑死颈畸,一個胖子當著我的面吹牛采桃,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播梆奈,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼褥芒,長吁一口氣:“原來是場噩夢啊……” “哼酒贬!你這毒婦竟也來了吧恃?” 一聲冷哼從身側(cè)響起虾啦,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后傲醉,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蝇闭,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年硬毕,在試婚紗的時候發(fā)現(xiàn)自己被綠了呻引。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡昭殉,死狀恐怖苞七,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情挪丢,我是刑警寧澤,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布卢厂,位于F島的核電站乾蓬,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏慎恒。R本人自食惡果不足惜任内,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望融柬。 院中可真熱鬧死嗦,春花似錦、人聲如沸粒氧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽外盯。三九已至摘盆,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間饱苟,已是汗流浹背孩擂。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留箱熬,地道東北人类垦。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像城须,于是被迫代替她去往敵國和親蚤认。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,435評論 2 359

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