1.背景介紹
什么是同步愤炸,什么是異步?
- 同步指的是一次只能完成一件任務(wù)。如果有多個任務(wù)矾睦,就必須排隊晦款,前面一個任務(wù)完成,再執(zhí)行后面一個任務(wù)枚冗,以此類推缓溅。
- 異步指的是每一個任務(wù)有一個或多個回調(diào)函數(shù)(callback),前一個任務(wù)結(jié)束后赁温,不是執(zhí)行后一個任務(wù)坛怪,而是執(zhí)行回調(diào)函數(shù),后一個任務(wù)則是不等前一個任務(wù)結(jié)束就執(zhí)行股囊,所以程序的執(zhí)行順序與任務(wù)的排列順序是不一致的袜匿、異步的。
2.知識剖析
javascript實現(xiàn)異步的原理
首先js是單線程的語言稚疹,即同一時間只能做做一件事居灯。那Js如何實現(xiàn)異步的,異步和單線程不是自相矛盾嗎内狗?其實怪嫌,單線程和異步確實不能同時成為一個語言的特性。js選擇了成為單線程的語言柳沙,所以它本身不可能是異步的岩灭,但js的宿主環(huán)境(比如瀏覽器,Node)是多線程的赂鲤,宿主環(huán)境通過某種方式(事件驅(qū)動噪径,下文會講)使得js具備了異步的屬性
瀏覽器的內(nèi)核是多線程的,它們在內(nèi)核制控下相互配合以保持同步蛤袒,一個瀏覽器至少實現(xiàn)三個常駐線程:javascript引擎線程熄云,UI渲染線程琼梆,瀏覽器事件觸發(fā)線程兔仰。
javascript引擎線程是基于事件驅(qū)動單線程執(zhí)行的,JS引擎一直等待著任務(wù)隊列中任務(wù)的到來杯巨,然后加以處理珍德,瀏覽器無論什么時候都只有一個JS線程在運行JS程序练般。
UI渲染線程負(fù)責(zé)渲染瀏覽器界面,當(dāng)界面需要重繪(Repaint)或由于某種操作引發(fā)回流(reflow)時,該線程就會執(zhí)行锈候。但需要注意UI渲染線程與JS引擎是互斥的薄料,當(dāng)JS引擎執(zhí)行時UI線程會被掛起,UI更新會被保存在一個隊列中等到JS引擎空閑時立即被執(zhí)行.
-
事件觸發(fā)線程泵琳,當(dāng)一個事件被觸發(fā)時該線程會把事件添加到待處理隊列的隊尾摄职,等待JS引擎的處理誊役。這些事件可來自JavaScript引擎當(dāng)前執(zhí)行的代碼塊如setTimeOut、也可來自瀏覽器內(nèi)核的其他線程如鼠標(biāo)點擊谷市、AJAX異步請求等蛔垢,但由于JS的單線程關(guān)系所有這些事件都得排隊等待JS引擎處理。
image
<input type="text" value="" name="input" onkeydown="console.log(this.value)">
<input type="text" value="" name="input" onkeydown="var me=this;setTimeout(function(){console.log(me.value)},0)">
分析:第一個在keydown的時候迫悠,彈出來的是input里原來的value鹏漆,而第2個在keydown的時候,卻能彈出更新后的value创泄,就是因為setTimeout艺玲,雖然他的delay設(shè)置為0,幾乎是即時觸發(fā)鞠抑,但還是被添加到了執(zhí)行隊列后面饭聚,但就是這個過程,渲染已經(jīng)完成了碍拆,當(dāng)他回調(diào)函數(shù)執(zhí)行時若治,輸出來的已經(jīng)是更新后的value了。
注意:js的工作機制是當(dāng)線程空閑的情況下才會執(zhí)行異步代碼的回調(diào)函數(shù)
即當(dāng)所有同步任務(wù)執(zhí)行完畢后才會執(zhí)行異步任務(wù)的回調(diào)函數(shù)
總結(jié):當(dāng)Js執(zhí)行到異步任務(wù)后感混,會將異步任務(wù)交給瀏覽器進行執(zhí)行端幼,當(dāng)執(zhí)行有結(jié)果時會把異步任務(wù)的回調(diào)函數(shù)插入待處理隊列的隊尾。
3.常見問題
- ajax發(fā)送異步請求瀏覽器做了什么
- 有哪些常見異步回調(diào)函數(shù)弧满?
4.解決方案
- ajax發(fā)送異步請求瀏覽器做了什么婆跑?
- Js創(chuàng)建了一個ajax請求
- 瀏覽器另外開啟一個ajax引擎線程,執(zhí)行ajax請求
- 執(zhí)行得到響應(yīng)后將回調(diào)函數(shù)放入任務(wù)隊列中庭呜。
- Js執(zhí)行任務(wù)隊列中的回調(diào)函數(shù)滑进。
- 有哪些常見的異步回調(diào)函數(shù)?
- 點擊事件
- Ajax請求
- 定時器
- 瀏覽器處理點擊事件的過程
- 瀏覽器開啟事件觸發(fā)線程募谎,等待用戶動作扶关,事件觸發(fā)線程解析為響應(yīng)事件,轉(zhuǎn)移到j(luò)avascript引擎線程数冬,排隊等候节槐,等待javascript引擎的處理。
例:
<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
</head>
<body>
<div onclick="clickme()">click me</div>
<script type="text/javascript">
function clickme() {
console.log('點擊事件')
}
for (i=0;i<50000;i++){
console.log(i)
}
</script>
</body>
</html>
在線實例
這個點擊事件會等到for循環(huán)執(zhí)行完畢后才會執(zhí)行拐纱,即我們點擊模塊它直到for循環(huán)執(zhí)行完畢才會執(zhí)行
5.編碼實戰(zhàn)
6.擴展思考
如何實現(xiàn)js的多線程操作铜异?
- Html5的web worker
7.更多討論
-
Q1:瀏覽器的UI線程和Js線程為什么是互斥的?
- A1:而因為JS可以操作DOM元素秸架,進而會影響到GUI的渲染結(jié)果揍庄,因此JS引擎線程與GUI渲染線程是互斥的。
-
Q2:異步函數(shù)有哪些優(yōu)點和缺點
- A2:
優(yōu)點:
a)對CPU的使用率高东抹。
b)不用考慮線程間同步互斥問題蚂子。
缺點:
a)實現(xiàn)較復(fù)雜沃测,要把所有會導(dǎo)致阻塞的操作轉(zhuǎn)化為異步操作。
b)并發(fā)性不好缆镣,在有的事件需要長時間占用CPU處理的情況下芽突,其他事件會長時間等待得不到處理。
c)在多CPU時不如多線程高效董瞻。 -
Q3:異步函數(shù)跟promise之間有什么關(guān)系?
A3:Promise它可以用于異步的回調(diào)函數(shù)田巴,它跟傳統(tǒng)的回調(diào)函數(shù)相比钠糊,promise的異步回調(diào)函數(shù)代碼書寫起來更優(yōu)雅,更便于閱讀壹哺。
8.參考文獻
參考一:js的單線程和異步
參考二:深入理解javascript異步編程障眼法&&h5 web worker實現(xiàn)多線程
參考三:談?wù)凧avaScript的異步實現(xiàn)- 小方- 博客園