我們常說 JavaScript 是單線程驳遵、異步淫奔、非阻塞的,但實(shí)際上同步/異步堤结、阻塞/非阻塞這兩組概念并非那么簡(jiǎn)單唆迁。通過研讀網(wǎng)絡(luò)上各位大神的文章,我來記錄一下竞穷,對(duì)于這兩組概念的理解唐责。
同步/異步
描述的是調(diào)用方與被調(diào)用方的關(guān)系
同步:
是指調(diào)用方發(fā)出請(qǐng)求后,被調(diào)用方在產(chǎn)生結(jié)果后才會(huì)返回瘾带,這樣調(diào)用的過程中參與雙方都處于一個(gè)狀態(tài)同步的過程鼠哥。
異步:
是指調(diào)用方發(fā)出請(qǐng)求就立即返回,請(qǐng)求甚至可能還沒到達(dá)被調(diào)用方,比如說放到了某個(gè)緩沖區(qū)中朴恳,等待對(duì)方取走或者第三方轉(zhuǎn)交抄罕;而結(jié)果,則通過被調(diào)用方主動(dòng)推送于颖,或調(diào)用方輪詢來得到呆贿。
阻塞/非阻塞
描述的是調(diào)用者自身的運(yùn)行狀態(tài)
阻塞:
調(diào)用者什么都不干,直至收到被調(diào)用者的通知森渐。
非阻塞:
調(diào)用者去干別的活做入,當(dāng)被調(diào)用者完成任務(wù)后,通知調(diào)用者同衣,調(diào)用者就可以處理被調(diào)用者的返回結(jié)果了竟块。(回調(diào)就是用來處理此時(shí)返回的結(jié)果)
二者的組合
同步&阻塞、異步&非阻塞
js中我們可以直觀理解耐齐,何為同步&阻塞浪秘,何為異步&非阻塞,在此不再贅述
同步&非阻塞
調(diào)用者發(fā)出調(diào)用之后(比如read)蚪缀,如果當(dāng)時(shí)有數(shù)據(jù)可讀秫逝,則讀取并返回,如果沒有數(shù)據(jù)可讀询枚,則線程繼續(xù)向下執(zhí)行。在實(shí)際使用時(shí)浙巫,read調(diào)用會(huì)在一個(gè)循環(huán)中金蜀,這樣就可以不斷的讀取數(shù)據(jù)(盡管可能某次read操作并不能獲得任何數(shù)據(jù),舉例:IO多路復(fù)用)
異步&阻塞
調(diào)用者發(fā)出調(diào)用之后(如async_recv)的畴,線程掛起渊抄,被調(diào)用者的讀操作由系統(tǒng)(或者庫(kù))來進(jìn)行,等待有結(jié)果之后丧裁,系統(tǒng)(或者庫(kù))通過某種機(jī)制來通知調(diào)用者(在調(diào)用者獲得結(jié)果之前护桦,調(diào)用者所在線程一直阻塞,這個(gè)看起來和同步阻塞很像煎娇,但可以這樣理解二庵,同步阻塞相當(dāng)于調(diào)用者A調(diào)用了一個(gè)函數(shù)F,F(xiàn)是在調(diào)用者A所在的線程中完成的缓呛,而異步阻塞相當(dāng)于調(diào)用者A發(fā)出對(duì)F的調(diào)用催享,然后A所在線程掛起,而實(shí)際F是在另一個(gè)線程中完成哟绊,然后另一個(gè)線程通知給A所在的線程因妙,更準(zhǔn)確的是將兩個(gè)線程分別換成用戶進(jìn)程和內(nèi)核)
JS中的場(chǎng)景
如果想實(shí)現(xiàn)同步&非阻塞,其實(shí)需要一個(gè)while循環(huán),在循環(huán)內(nèi)沒有阻塞攀涵,但整個(gè)event loop仍然是阻塞的铣耘,所以意義不大。
如果想實(shí)現(xiàn)異步&阻塞以故,其實(shí)就是想發(fā)起異步請(qǐng)求后涡拘,掛起線程內(nèi)的所有操作,可以設(shè)置一個(gè)標(biāo)志位据德,在標(biāo)志位不改變之前鳄乏,不執(zhí)行任何其他task,但顯然這也是多此一舉棘利。
因此橱野,JS的event loop機(jī)制,已經(jīng)決定了只有同步&阻塞善玫、異步&非阻塞是有意義的水援。