您好,登錄后才能下訂單哦!
相信不少人對Javascript單線程表示懷疑:為何單線程可以實現(xiàn)異步操作呢?其實Javascript確實是單線程的(我們不妨把這個線程稱作主線程),但它實現(xiàn)異步操作的方式確實借助了瀏覽器的其他線程的幫助。那其他線程是怎么幫助Javascript主線程來實現(xiàn)異步的呢?答案就是任務(wù)隊列(task queue)和事件循環(huán)(event loop)。
任務(wù)隊列
首先,作為單線程語言,在Javascript中定義的任務(wù)都會在主線程中執(zhí)行。但是并不是每個任務(wù)都會立刻執(zhí)行,而這種不立刻執(zhí)行的任務(wù)我們稱作異步任務(wù)。相反,那些立刻執(zhí)行的任務(wù)我們把它們稱作同步任務(wù)。而這些異步任務(wù)都會交給瀏覽器的其他線程去執(zhí)行,但是主線程需要了解這些異步任務(wù)執(zhí)行的狀態(tài),才方便進行下一步操作。
打個比方,主線程準(zhǔn)備做飯,所以下達一個異步任務(wù)去買菜,異步任務(wù)買完菜之后得告訴主線程:“我買完菜啦”,這個時候主線程才好開始做飯。
而我們知道因為Javascript是單線程,所以上述的“下一步操作”沒法直接定義在主函數(shù)里(不然就被當(dāng)做同步任務(wù)直接執(zhí)行了),那這些應(yīng)該定義在哪里呢?答案就是異步任務(wù)的回調(diào)函數(shù)中。在Javascript異步機制中,任務(wù)隊列就是用來維護異步任務(wù)回調(diào)函數(shù)的隊列。這樣一個隊列用來存放這些回調(diào)函數(shù),它們會等到主線程執(zhí)行完所有的同步函數(shù)之后按照先進先出的方式挨個執(zhí)行。那么執(zhí)行完任務(wù)隊列之后呢?Javascript主線程就執(zhí)行完畢了嗎?當(dāng)然不是,不然網(wǎng)頁加載完畢之后,誰來處理后續(xù)與用戶的交互事件(比如點擊事件)呢?
事件循環(huán)
我們通過上圖來更加形象的了解Javascript的異步機制。
執(zhí)行同步任務(wù) -> 檢查任務(wù)隊列中是否有任務(wù) -> [有如果則執(zhí)行] -> 檢查任務(wù)隊列中是否有任務(wù) -> [有如果則執(zhí)行] -> ......
可見主線程在執(zhí)行完同步任務(wù)之后,會無限循環(huán)地去檢查任務(wù)隊列中是否有新的“任務(wù)”,如果有則執(zhí)行。而這些任務(wù)包括我們在異步任務(wù)中定義的回調(diào)函數(shù),也包括用戶交互事件的回調(diào)函數(shù)。通過事件循環(huán),Javascript不僅很好的處理了異步任務(wù),也很好的完成了與用戶交互事件的處理。因為在完成異步任務(wù)的回調(diào)函數(shù)之后,任務(wù)隊列中的任務(wù)都是由事件所產(chǎn)生的,因此我們也把上述的循環(huán)過程叫做事件循環(huán)。
異步機制實踐
console.log('定時器去買菜吧') setTimeout(function(){ console.log('菜買完了,主線程去做菜吧') }, 0) console.log('你先去買菜,我先看個世界杯')
在瀏覽器中執(zhí)行上述代碼,興許能更好地理解Javascript的異步機制。
總結(jié)
總而言之,Javascript單線程的背后有瀏覽器的其他線程為其完成異步服務(wù),這些異步任務(wù)為了和主線程通信,通過將回調(diào)函數(shù)推入到任務(wù)隊列等待執(zhí)行。主線程所做的就是執(zhí)行完同步任務(wù)后,通過事件循環(huán),不斷地檢查并執(zhí)行任務(wù)隊列中回調(diào)函數(shù)。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。