最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

一文了解你不知道的JavaScript異步篇

 更新時間:2022年11月09日 10:31:40   作者:霍格沃茨魔法師  
這篇文章主要為大家詳細介紹了一些你不知道的JavaScript異步相關知識,文中的示例代碼講解詳細,對我們學習JavaScript有一定幫助,感興趣的可以跟隨小編一起學習一下

事件循環(huán)

先通過一段偽代碼了解一下事件循環(huán)這個概念

//eventLoop是一個用作隊列的數(shù)組
var eventLoop = []
var event;
//永遠執(zhí)行
while(true){
   if(eventLoop.length>0){}
    //拿到隊列中的下一個事件
    event = eventLoop.shift();
    //現(xiàn)在,執(zhí)行下一個事件
    try{
      event()
    }
    catch(err){
     reportError(err)
    }
}

這是一段繼續(xù)簡化的代碼,你可以看到有一個用while循環(huán)實現(xiàn)的持續(xù)運行的循環(huán),循環(huán)的每一輪稱為一個tick。對每個tick而言,如果在隊列中有等待事件,就會從隊列中摘下一個事件并執(zhí)行,這些事件就是所謂的回調(diào)函數(shù)。

一定要清楚,setTimeout()并沒有把你的回調(diào)函數(shù)掛在事件循環(huán)隊列中。他所做的是設定一個定時器。當定時器到時后,環(huán)境會把你的回調(diào)函數(shù)放在事件循環(huán)中,這樣,在未來某個時刻的tick會摘下并執(zhí)行這個回調(diào)。所以這也是為什么setTimeout時間精度可能不太高,它只能確保你的回調(diào)函數(shù)不會在指定的時間間隔之前運行,但可能會在事件循環(huán)隊列中20個項目后才執(zhí)行。取決于你事件隊列的項目與狀態(tài),畢竟JavaScript一次只能處理一個事件。這也引出了另一個概念“并發(fā)”。

當兩個或多個“進程”同時執(zhí)行就出現(xiàn)了并發(fā),也許瀏覽器會發(fā)出很多請求,當發(fā)出第二個請求時,第一個請求返回響應,當發(fā)出第三個請求時,第二個請求返回響應。這里請求2與響應1并發(fā)運行,請求3與響應2并發(fā)運行,但是他們的各個事件是在事件循環(huán)隊列中依次運行的。

更常見一點的情況是,并發(fā)的“進程”需要相互交流,如果出現(xiàn)這樣的交互,就需要對他們的交互進行協(xié)作以避免競態(tài)的出現(xiàn)。下面是兩個并發(fā)的進程通過隱含的順序相互影響,這個順序有時會被破壞:

var res = [];
function response(data){
    res.push(data)
}
ajax("http://url1",response);
ajax("http://url2",response);

這里的兩個ajax去調(diào)用response函數(shù),但不確定哪一會先執(zhí)行完成,這種不確定性很有可能就是一個競態(tài)條件bug。

在es6中,有一個新的概念建立在事件循環(huán)隊列之上,解決這種不確定性的執(zhí)行,叫做任務隊列。

任務隊列

對任務隊列最好的理解方式就是,它是掛在事件循環(huán)隊列的每個tick之后的一個隊列。在事件循環(huán)的每個tick中??赡艹霈F(xiàn)的異步動作不會導致一個完整的新事件添加到事件循環(huán)隊列中,而會在當前tick的任務隊列末尾添加一個任務。

任務隊列意思是:哦?原來這里還有一件事情要做,但要在任何事情發(fā)生之前就完成它,立刻接著執(zhí)行它。

而事件循環(huán)類似于做完這件事情,需要重新到隊尾排隊才能再做這件事情。

console.log("A")
setTimeout(()=>{
    console.log("B")
},0)
task(()=>{
console.log("C")
    task(()=>{
      console.log('D')
    })
})

可能你認為這里會打印出ABCD,但其實打印結果是ACDB,因為定時器觸發(fā)是在所有同步事件隊列清空之后才開始執(zhí)行的。

回調(diào)

到目前位置,回調(diào)是編寫和處理JavaScript程序異步邏輯的最常用的方式,也是最基礎的異步模式。

我們的大腦可以看作類似于單線程運行的事件循環(huán)隊列,就像JavaScript引擎那樣。用正在寫博客的我寫作進行類比。此刻我心里就是計劃寫啊寫一直寫,一次完成我腦海中已經(jīng)按順序排好的一系列要點。我沒有將任何終端或非線性的行為納入到我的寫作計劃中。然而盡管如此,實際上我的大腦還是在不停的切換狀態(tài)。即使我的大腦在以異步事件方式運行,但我的寫作還是以順序、同步的進行,“先寫這里,再寫那里”。

所以,如果說同步的大腦計劃能夠很好地映射到同步代碼語句,那么我們大腦在規(guī)劃異步方面又是怎樣的呢?

答案是回調(diào)。即使在腦海中有許多事件出現(xiàn),如果真的想到什么就做什么去那恐怕我這篇博客也無法完成。但在實際執(zhí)行方面,我的大腦就是這樣運作了。不是多任務,而是快速的上下文切換。

嵌套回調(diào)

listen("click",()=>{
    setTimeout(()=>{
     setTimeout(()=>{
       ajax("http:url",()=>{
          console.log("響應結果")
       })
    },1000)
},1000)
})

你可能非常熟悉這樣的代碼,好幾個函數(shù)嵌套在一起構成的鏈,這種代碼常常被稱為回調(diào)地獄問題,在大型項目中他引起的問題要比這些嚴重得多。為了避免回調(diào)地獄問題,產(chǎn)生了偉大的promise。

promise

在promise中,傳入的函數(shù)會立刻執(zhí)行,它有兩個參數(shù),在本例中我們將其分別稱為resolve和reject。前者代表完成,后者代表拒絕。

new Promise((resolve,reject)=>{
   //最終調(diào)用resolve還是reject
}).then(
  function(){
   console.log("then")
  }
)

promise調(diào)度技巧

如果兩個promise都已經(jīng)決議,那么p1.then和p2.then應該最終會先調(diào)用p1的回調(diào),然后是p2的哪些,但還有一些可能微妙的場景:

p.then(function(){
  p.then(function(){
    console.log("C")
  })
  console.log("A")
})
p.then(function(){
   console.log("B")
})

這里的輸出結果是 A B C

一個promise決議后,這個promise上所有的通過then注冊的回調(diào)都會在下一個異步時機點上一次調(diào)用。所以在這里'C'無法搶占或打斷‘B’,因為這是promise的運作方式。

錯誤處理

對于大多數(shù)開發(fā)者來說,最自然的錯誤處理就是try...catch結構,遺憾的是它只能是同步的,無法用于異步代碼模式。

function(){
  setTimeout(()=>{
    bar()
  },1000)
}
try{
  foo()
}catch(err){
   //永遠不會到達這里
}

try...catch當然很好,但是無法跨越異步操作工作,所以catch無法攔截定時器內(nèi)異步的錯誤。

方法1. 可以在then(resolve,reject)中第二個回調(diào)內(nèi)處理錯誤,可以throw傳遞一個error。

方法2. finally捕獲

不管promise最后的狀態(tài),在執(zhí)行完then或catch指定的回調(diào)函數(shù)之后,都會執(zhí)行finally方法指定的回調(diào)函數(shù)。

function fn(val){
    return new Promise((resolve,reject)=>{
        if(val){
          resolve({name:"111"})
        }else{
          reject("404")
        }
    })
}
//執(zhí)行函數(shù)
fn(true)
   .then(data=>{
     console.log(data) //打印name:111鍵值對
     return fn(false)
   })
   .catch(e=>{
     console.log(e) //打印404
     return fn(false)
   })
   .finally(()=>{
     console.log("finally") //會打印的!
   })

promise.all([...])

假如你想同時發(fā)送兩個請求,等他們不管以什么順序完成之后再發(fā)送第三個請求

Promise.all([p1,p2])
.then(function(){
    return request("http:url3")
})
.then(function(msg){
  console.log(msg)
})

Promise.all需要一個參數(shù),是一個數(shù)組,通常由promise實例組成,從promise.all調(diào)用返回的promise會收到一個完整消息(msg)。這是一個由數(shù)組完成后傳入的消息,與順序無關。

另外,當數(shù)組內(nèi)有且僅有所有成員promise都完成后才算完成。如果這些promise有任何一個被拒絕那all就會立刻被拒絕,并丟棄已經(jīng)成功的來自其他數(shù)組成員的promise結果。

promise.race([...])

盡管promise.all協(xié)調(diào)多個并發(fā)promise的運行,并假定所有都需要完成,但有時候你會只想響應第一個完成promise的結果,并直接拋棄其他promise。

這種在promise中被稱之為競態(tài)。

promise.race()也接受一個數(shù)組做參數(shù)。這個數(shù)組有一個/多個promise組成。一旦有任何一個promise為成功resolve,promise.race()就會完成;一旦有任何一個為reject被拒絕,它就會拒絕。

(如果你傳入一個空數(shù)組,那race永遠不會resolve,永遠不要傳遞空數(shù)組)

Promise.race([p1,p2])
.then(function(){
//p1和p2其中之一會完成這場競賽,突破重圍
    return request("http:url3")
})
.then(function(msg){
  console.log(msg)
})

因為只有一個promise能夠取勝,所以完成值是單個消息,而不是像all一樣是一個數(shù)組。

all和race的變體

· none([...])

這個模式類似于all([...]),不過完成和拒絕的情況互換了,而是所有的promise都要被拒絕,即拒絕轉化為完成值。

· any([...])

這個模式與all([...])類似,但是會忽略拒絕,所以只需要完成一個而不是全部。

· first([...])

這個模式類似于與any([...])的競爭,即只要第一個promise完成,就會忽略后續(xù)的任何完成和拒絕。

· last([...])

這個模式類似于first([...]),但卻是只有最后一個完成勝出。

無法取消的promise

一旦創(chuàng)建了一個promise并為其注冊了完成/拒絕的處理函數(shù),如果出現(xiàn)某種情況使得這個任務懸而未決的話,你也沒有辦法從外部停止它的進程。

以上就是一文了解你不知道的JavaScript異步篇的詳細內(nèi)容,更多關于JavaScript異步的資料請關注腳本之家其它相關文章!

相關文章

  • JavaScript中0、空字符串、''0''是true還是false的知識點分享

    JavaScript中0、空字符串、''0''是true還是false的知識點分享

    在本篇文章里小編給大家整理的是JavaScript中0、空字符串、'0'是true還是false的知識點分享,有需要的朋友們參考下。
    2019-09-09
  • DIV始終居中的js代碼

    DIV始終居中的js代碼

    這篇文章主要介紹了DIV始終居中的js代碼,需要的朋友可以參考下
    2014-02-02
  • QQ跳轉支付寶并自動領紅包腳本(最新)

    QQ跳轉支付寶并自動領紅包腳本(最新)

    這篇文章主要給大家分享介紹了一個QQ跳轉支付寶并自動領紅包腳本,這個腳本應該是最新的,測試后是可以使用的,文中給出了完整的示例代碼和使用方法,需要的朋友可以參考借鑒,下面隨著小編來一起學習學習吧
    2018-06-06
  • JavaScript 10件讓人費解的事情

    JavaScript 10件讓人費解的事情

    JavaScript 可算是世界上最流行的編程語言,它曾被 Web 開發(fā)設計師貼上噩夢的標簽,雖然真正的噩夢其實是 DOM API,這個被大量的開發(fā)與設計師隨手拈來增強他們的 Web 前端的腳本語言,如今越來越被重視,雖則如此,JavaScript 仍然擁有很多讓人費解的東西。
    2010-02-02
  • 基于JS實現(xiàn)簡單滑塊拼圖游戲

    基于JS實現(xiàn)簡單滑塊拼圖游戲

    本文通過實例代碼給大家介紹了JS實現(xiàn)簡單滑塊拼圖游戲,代碼簡單易懂,非常不錯,具有一定的參考借鑒價值,需要的朋友參考下吧
    2019-10-10
  • ES6 Generator函數(shù)的應用實例分析

    ES6 Generator函數(shù)的應用實例分析

    這篇文章主要介紹了ES6 Generator函數(shù)的應用,結合實例形式分析了ES6 Generator函數(shù)異步操作與異常捕獲相關使用技巧,需要的朋友可以參考下
    2019-06-06
  • ES6學習教程之模板字符串詳解

    ES6學習教程之模板字符串詳解

    大家都知道在ES6中引進的一種新型的字符串字面量語法-模板字符串,下面這篇文章主要給大家介紹了關于ES6學習教程之模板字符串的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧。
    2017-10-10
  • javascript獲取ckeditor編輯器的值(實現(xiàn)代碼)

    javascript獲取ckeditor編輯器的值(實現(xiàn)代碼)

    這篇文章主要介紹了javascript獲取ckeditor編輯器的值,用于表單驗證。需要的朋友可以過來參考下,希望對大家有所幫助
    2013-11-11
  • JavaScript實現(xiàn)身份證驗證代碼實例

    JavaScript實現(xiàn)身份證驗證代碼實例

    這篇文章主要介紹了JavaScript實現(xiàn)身法證驗證代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-08-08
  • JavaScript基于querySelector?/?querySelectorAll對元素的操作(DOM?API掃盲)

    JavaScript基于querySelector?/?querySelectorAll對元素的操作(DOM?AP

    這篇文章主要介紹了JavaScript基于querySelector?/?querySelectorAll對元素的操作(DOM?API掃盲),本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2023-12-12

最新評論

镇江市| 通化市| 古丈县| 大安市| 双辽市| 北碚区| 新竹市| 清水县| 玉山县| 临高县| 遂溪县| 郓城县| 库尔勒市| 子长县| 洪雅县| 南阳市| 河东区| 林甸县| 根河市| 贡山| 陆丰市| 来凤县| 石林| 浦县| 华蓥市| 阳山县| 九江市| 通榆县| 家居| 都兰县| 醴陵市| 和龙市| 茌平县| 大悟县| 溧阳市| 兰溪市| 婺源县| 丹凤县| 惠安县| 昌吉市| 横峰县|