今天我們廣州藍(lán)景實訓(xùn)部,和大家做一下技術(shù)分享,關(guān)于“JS里的同步和異步”,希望幫助到大家
最近發(fā)現(xiàn)挺多人在學(xué)習(xí)js的時候,比較難理解同步和異步的;特別在剛學(xué)習(xí)到定時器時,我們設(shè)置定時器延遲執(zhí)行的時間,JS真的會準(zhǔn)確按照這個時間間隔來執(zhí)行嗎?
下面我們就從定時器開始慢慢聊一下這個話題。
首先要明確兩點:
[if !supportLists]1.?[endif]JS執(zhí)行機制是單線程。
[if !supportLists]2.?[endif]JS的Event loop是JS的執(zhí)行機制,深入了解Event loop,就等于深入了解JS引擎的執(zhí)行。
單線程執(zhí)行帶來什么問題?
在JS執(zhí)行中都是單線程執(zhí)行,所以代碼的執(zhí)行可以說是自上而下,如果前一段的代碼比較耗時或者出錯,就會導(dǎo)致下一段代碼的阻塞現(xiàn)象,直觀一點就是用戶能感受到的的卡頓或者崩潰,所以在JS執(zhí)行機制引出了異步執(zhí)行操作。
那異步能解決什么問題,又會帶來什么問題?
異步操作能夠很好的解決上面單線程執(zhí)行出現(xiàn)的卡死現(xiàn)象,但是也會產(chǎn)生問題,比如同時對一件事情操作,不知道應(yīng)該先執(zhí)行那件事。
那么同步中使用異步如何實現(xiàn)呢?
是通過的事件循環(huán)(Event loop)那先了解下Event loop吧。
先看一下,以下代碼:
[if !supportLists]1.?[endif]console.log("1");
[if !supportLists]2.?[endif]setTimeout(function(){
[if !supportLists]3.?[endif]console.log("2");
[if !supportLists]4.?[endif]},0);
[if !supportLists]5.?[endif]console.log("3");
運行結(jié)果是:1、3、2
總所周知setTimeout里的函數(shù)不會立即執(zhí)行,而是延遲一段時間,符合特定的條件才開始執(zhí)行,這就是異步執(zhí)行操作。
JS中所有任務(wù)可以分成兩種,一種是同步任務(wù),另一種是異步任務(wù)(如各種瀏覽器事件、定時器和Ajax等)。同步任務(wù)指的是,在主線程上排隊執(zhí)行的任務(wù),只有前一個任務(wù)執(zhí)行完畢,才能執(zhí)行后一個任務(wù);異步任務(wù)指的是,不進(jìn)入主線程、而進(jìn)入"任務(wù)隊列"(task queue)的任務(wù),只有"任務(wù)隊列"通知主線程,某個異步任務(wù)可以執(zhí)行了,該任務(wù)才會進(jìn)入主線程執(zhí)行。
直接結(jié)合圖例來說明:
[if !supportLists]1.?[endif]所有同步任務(wù)都在主線程上執(zhí)行,形成一個執(zhí)行棧(execution context stack)。
[if !supportLists]2.?[endif]主線程之外,還存在一個"任務(wù)隊列"(task queue)。只要異步任務(wù)有了運行結(jié)果,就在"任務(wù)隊列"之中放置一個事件。
[if !supportLists]3.?[endif]一旦"執(zhí)行棧"中的所有同步任務(wù)執(zhí)行完畢,系統(tǒng)就會讀取"任務(wù)隊列",看看里面有哪些事件。那些對應(yīng)的異步任務(wù),于是結(jié)束等待狀態(tài),進(jìn)入執(zhí)行棧,開始執(zhí)行。
[if !supportLists]4.?[endif]主線程不斷重復(fù)上面的第三步。

簡單總結(jié)一下:JS要做的就是執(zhí)行"執(zhí)行棧"里的任務(wù),完成所有的同步任務(wù)(JS主線程)后才去讀取"任務(wù)隊列"中讀取任務(wù)并且添加到"執(zhí)行棧"中執(zhí)行,這個過程不斷循環(huán)。
那么看完以上的分析,回歸到我們文章的第一個疑問,假設(shè)我們設(shè)置定時器的1000ms,JS真的在1000ms后執(zhí)行嗎??
以上就是我們廣州藍(lán)景實訓(xùn)部,給大家的技術(shù)分享小結(jié),希望大家繼續(xù)多多支持我們廣州藍(lán)景實訓(xùn)部。