成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

JavaScript同步和異步

Eirunye / 2243人閱讀

摘要:異步如果在函數(shù)返回的時候,調(diào)用者還不能購得到預(yù)期結(jié)果,而是將來通過一定的手段得到例如回調(diào)函數(shù),這就是異步。的意思是,將回調(diào)函數(shù)立刻插入消息隊列,等待執(zhí)行,而不是立即執(zhí)行。

大家好,我是wmingren,小伙伴們都知道JavaScript是單線程的語言,所謂的單線程呢就是指如果有多個任務(wù)就必須去排隊,前面任務(wù)執(zhí)行完成后,后面任務(wù)再執(zhí)行。到這里我們就產(chǎn)生了一個疑問,既然是單線程的,又怎么會有異步操作呢?首先了解一下同步和異步的概念吧。
一、同步和異步

同步
如果在函數(shù)返回結(jié)果的時候,調(diào)用者能夠拿到預(yù)期的結(jié)果(就是函數(shù)計算的結(jié)果),那么這個函數(shù)就是同步的.
console.log("hello");//執(zhí)行后,獲得了返回結(jié)果

如果函數(shù)是同步的,即使調(diào)用函數(shù)執(zhí)行任務(wù)比較耗時,也會一致等待直到得到執(zhí)行結(jié)果。如下面的代碼:

function wait(){
    var time = (new Date()).getTime();//獲取當(dāng)前的unix時間戳
    while((new Date()).getTime() - time > 5000){}
    console.log("5秒過去了");
}
wait();
console.log("慢死了");

上面代碼中,函數(shù)wait是一個耗時程序,持續(xù)5秒,在它執(zhí)行的這漫長的5秒中,下面的console.log()函數(shù)只能等待,這就是同步。

異步
如果在函數(shù)返回的時候,調(diào)用者還不能購得到預(yù)期結(jié)果,而是將來通過一定的手段得到(例如回調(diào)函數(shù)),這就是異步。例如ajax操作。  
如果函數(shù)是異步的,發(fā)出調(diào)用之后,馬上返回,但是不會馬上返回預(yù)期結(jié)果。調(diào)用者不必主動等待,當(dāng)被調(diào)用者得到結(jié)果之后會通過回調(diào)函數(shù)主動通知調(diào)用者。
二、單線程與多線程
了解完同步和異步之后,我們再來看看我們的問題:單線程又怎么會有異步呢?  
JavaScript其實就是一門語言,說是單線程還是多線程得結(jié)合具體運行環(huán)境。眾所周知,js的運行環(huán)境就是瀏覽器,具體由js引擎取解析和執(zhí)行。下面我們來了解下瀏覽器。
瀏覽器

一個瀏覽器通常由以下幾個常駐的線程:

渲染引擎線程,負(fù)責(zé)頁面的渲染

js引擎線程,負(fù)責(zé)js的解析和執(zhí)行

定時觸發(fā)器線程,處理setInterval和setTimeout

事件觸發(fā)線程,處理DOM事件

異步http請求線程,處理http請求

要注意的是渲染引擎和js引擎線程是不能同時進行的。渲染線程在執(zhí)行任務(wù)的時候,js引擎線程會被掛起。因為若是在渲染頁面的時候,js處理了DOM,瀏覽器就不知道該聽誰的了
JS引擎
通常講到瀏覽器的時候,我們會說到兩個引擎:渲染引擎和JS引擎。
1、渲染引擎:Chrome/Safari/Opera用的是Webkit引擎,IE用的是Trdent引擎,F(xiàn)ireFox用的是Gecko引擎。不同的引擎對同一個樣式的實現(xiàn)不一致,就導(dǎo)致瀏覽器的兼容性問題。
2、JS引擎:js引擎可以說是js虛擬機,負(fù)責(zé)解析js代碼的解析和執(zhí)行。通常有以下步驟:

詞法解析:將源代碼分解位有意義的分詞

語法分析:用語法分析器將分詞解析成語法樹

代碼生成:生成機器能運行的代碼

代碼執(zhí)行

不同瀏覽器的js引擎也各不相同,Chrome用的是V8,F(xiàn)ireFox用的是SpiderMonkey,Safari用的是JavaScriptCore,IE用的是Chakra。  

之所以說js是單線程就是因為瀏覽器運行時只開啟一個js解釋器,原因是若有兩個線程操作DOM,瀏覽器就又暈了。

JavaScript是單線程的,但是瀏覽器不是單線程的。一些I/O操作,定時器的計時和事件監(jiān)聽是由其他線程完成的。

三、消息隊列與事件循環(huán)
由上面瀏覽器一篇的介紹可以知道,瀏覽器中多個線程的合作完成了異步的操作,那么異步的回調(diào)函數(shù)又是怎樣完成執(zhí)行的呢?  

這就需要了解消息隊列和事件循環(huán)了。

如上圖所示,左邊的棧存儲的是同步任務(wù),就是那些能立即執(zhí)行、不耗時的任務(wù),如變量和函數(shù)的初始化、事件的綁定等等那些不需要回調(diào)函數(shù)的操作都可歸為這一類。

右邊的堆用來存儲聲明的變量、對象。下面的隊列就是消息隊列,一旦某個異步任務(wù)有了響應(yīng)就會被推入隊列中。如用戶的點擊事件、瀏覽器收到服務(wù)的響應(yīng)和setTimeout中待執(zhí)行的事件,每個異步任務(wù)都和回調(diào)函數(shù)相關(guān)聯(lián)。

JS引擎線程用來執(zhí)行棧中的同步任務(wù),當(dāng)所有同步任務(wù)執(zhí)行完畢后,棧被清空,然后讀取消息隊列中的一個待處理任務(wù),并把相關(guān)回調(diào)函數(shù)壓入棧中,單線程開始執(zhí)行新的同步任務(wù)。

JS引擎線程從消息隊列中讀取任務(wù)是不斷循環(huán)的,每次棧被清空后,都會在消息隊列中讀取新的任務(wù),如果沒有新的任務(wù),就會等待,直到有新的任務(wù),這就叫事件循環(huán)。

上圖以AJAX異步請求為例,發(fā)起異步任務(wù)后,由AJAX線程執(zhí)行耗時的異步操作,而JS引擎線程繼續(xù)執(zhí)行堆中的其他同步任務(wù),直到堆中的所有異步任務(wù)執(zhí)行完畢。然后,從消息隊列中依次按照順序取出消息作為一個同步任務(wù)在JS引擎線程中執(zhí)行,那么AJAX的回調(diào)函數(shù)就會在某一時刻被調(diào)用執(zhí)行。

四、實例
最后來一個經(jīng)典的面試題來幫助大家理解js的同步和異步。
代碼如下:
//執(zhí)行下面這段代碼,執(zhí)行后,在 5s 內(nèi)點擊兩下,過一段時間(>5s)后,再點擊兩下,整個過程的輸出結(jié)果是什么?
setTimeout(function(){
    for(var i = 0; i < 100000000; i++){}
    console.log("timer a");
}, 0)

for(var j = 0; j < 5; j++){
    console.log(j);
}

setTimeout(function(){
    console.log("timer b");
}, 0)

function waitFiveSeconds(){
    var now = (new Date()).getTime();
    while(((new Date()).getTime() - now) < 5000){}
    console.log("finished waiting");
}

document.addEventListener("click", function(){
    console.log("click");
})

console.log("click begin");
waitFiveSeconds();

要想了解上述代碼的輸出結(jié)果,首先介紹下定時器。

setTimeout 的作用是在間隔一定的時間后,將回調(diào)函數(shù)插入消息隊列中,等棧中的同步任務(wù)都執(zhí)行完畢后,再執(zhí)行。因為棧中的同步任務(wù)也會耗時, 所以間隔的時間一般會大于等于指定的時間 。

setTimeout(fn, 0) 的意思是,將回調(diào)函數(shù)fn立刻插入消息隊列,等待執(zhí)行,而不是立即執(zhí)行??匆粋€例子:

setTimeout(function() {
    console.log("a")
}, 0)

for(let i=0; i<10000; i++) {}
console.log("b")
//打印結(jié)果,說明回調(diào)函數(shù)沒有立即執(zhí)行,而是等待同步任務(wù)執(zhí)行完成后才執(zhí)行的
b a
下面來解釋一下面試題吧。

先執(zhí)行同步任務(wù),for循環(huán),然后是console.log("click begin") 最后是waitFiveSeconds函數(shù)

在同步任務(wù)執(zhí)行的期間,‘timera’,‘timerb’對應(yīng)的回調(diào)和click事件的回調(diào)先后入隊列。

同步任務(wù)結(jié)束后,js引擎線程空閑后會線查看是否有事件可執(zhí)行,接著在處理其他異步任務(wù),因此會有下面的輸出:

0
1
2
3
4
click begin
finished waiting
2 click  //5s中兩次點擊
timer a
timer b
2 click  //5s后兩次點擊

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/107056.html

相關(guān)文章

  • 前端面試:js同步異步問題

    摘要:今天的已經(jīng)成為一門功能全面的編程語言總結(jié)最初的用途是為來實現(xiàn)用戶與瀏覽器的交互二為何是單線程的的單線程,與它的用途有關(guān)。這決定了它只能是單線程,否則會帶來很復(fù)雜的同步問題。 showImg(https://user-gold-cdn.xitu.io/2019/3/31/169d1c40c27a173c?w=428&h=252&f=png&s=35393); 前言 我本來是打算寫一篇co...

    call_me_R 評論0 收藏0
  • 淺析JavaScript異步

    摘要:回調(diào)函數(shù),一般在同步情境下是最后執(zhí)行的,而在異步情境下有可能不執(zhí)行,因為事件沒有被觸發(fā)或者條件不滿足。同步方式請求異步同步請求當(dāng)請求開始發(fā)送時,瀏覽器事件線程通知主線程,讓線程發(fā)送數(shù)據(jù)請求,主線程收到 一直以來都知道JavaScript是一門單線程語言,在筆試過程中不斷的遇到一些輸出結(jié)果的問題,考量的是對異步編程掌握情況。一般被問到異步的時候腦子里第一反應(yīng)就是Ajax,setTimse...

    Tangpj 評論0 收藏0
  • JavaScript系列——JavaScript同步、異步、回調(diào)執(zhí)行順序之經(jīng)典閉包setTimeou

    摘要:同步異步回調(diào)傻傻分不清楚。分割線上面主要講了同步和回調(diào)執(zhí)行順序的問題,接著我就舉一個包含同步異步回調(diào)的例子。同步優(yōu)先回調(diào)內(nèi)部有個,第二個是一個回調(diào)回調(diào)墊底。異步也,輪到回調(diào)的孩子們回調(diào),出來執(zhí)行了。 同步、異步、回調(diào)?傻傻分不清楚。 大家注意了,教大家一道口訣: 同步優(yōu)先、異步靠邊、回調(diào)墊底(讀起來不順) 用公式表達(dá)就是: 同步 => 異步 => 回調(diào) 這口訣有什么用呢?用來對付面試的...

    lewif 評論0 收藏0
  • JavaScript系列——JavaScript同步、異步、回調(diào)執(zhí)行順序之經(jīng)典閉包setTimeou

    摘要:同步異步回調(diào)傻傻分不清楚。分割線上面主要講了同步和回調(diào)執(zhí)行順序的問題,接著我就舉一個包含同步異步回調(diào)的例子。同步優(yōu)先回調(diào)內(nèi)部有個,第二個是一個回調(diào)回調(diào)墊底。異步也,輪到回調(diào)的孩子們回調(diào),出來執(zhí)行了。 同步、異步、回調(diào)?傻傻分不清楚。 大家注意了,教大家一道口訣: 同步優(yōu)先、異步靠邊、回調(diào)墊底(讀起來不順) 用公式表達(dá)就是: 同步 => 異步 => 回調(diào) 這口訣有什么用呢?用來對付面試的...

    rockswang 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<