国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

詳解JS的四種異步解決方案!

這篇具有很好參考價(jià)值的文章主要介紹了詳解JS的四種異步解決方案!。希望對大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

目錄

同步&異步的概念

js中異步的應(yīng)用場景

實(shí)現(xiàn)異步的四種方法

1、 回調(diào)函數(shù)

2、Promise

3、Generator

4、 async/await


????????「異步編程」是前端工程師日常開發(fā)中經(jīng)常會用到的技術(shù),也是校招面試過程中??嫉囊粋€(gè)知識點(diǎn)。

????????通過掌握「異步編程」的四種方式,可以讓我們能夠更好地處理JavaScript中的異步操作,提高代碼的性能和用戶體驗(yàn)。

????????因此,「今天就想和大家來聊聊JS異步編程的四種方式!」

同步&異步的概念

在講這四種異步方案之前,我們先來明確一下同步和異步的概念:

????????所謂「同步(synchronization)」,簡單來說,就是「順序執(zhí)行」,指的是同一時(shí)間只能做一件事情,只有目前正在執(zhí)行的事情做完之后,才能做下一件事情。

????????「同步操作的優(yōu)點(diǎn)」在于做任何事情都是依次執(zhí)行,井然有序,不會存在大家同時(shí)搶一個(gè)資源的問題。

????????「同步操作的缺點(diǎn)」在于「會阻塞后續(xù)代碼的執(zhí)行」。如果當(dāng)前執(zhí)行的任務(wù)需要花費(fèi)很長的時(shí)間,那么后面的程序就只能一直等待。

????????所謂「異步(Asynchronization)」,指的是當(dāng)前代碼的執(zhí)行不影響后面代碼的執(zhí)行。當(dāng)程序運(yùn)行到異步的代碼時(shí),會將該異步的代碼作為任務(wù)放進(jìn)「任務(wù)隊(duì)列」,而不是推入主線程的調(diào)用棧。等主線程執(zhí)行完之后,再去任務(wù)隊(duì)列里執(zhí)行對應(yīng)的任務(wù)即可。

????????因此,「異步操作的優(yōu)點(diǎn)就是:不會阻塞后續(xù)代碼的執(zhí)行?!?/strong>

js中異步的應(yīng)用場景

開篇講了同步和異步的概念,那么在JS中異步的應(yīng)用場景有哪些呢?

  • 「定時(shí)任務(wù)」:setTimeout、setInterval

  • 「網(wǎng)絡(luò)請求」:ajax請求、動態(tài)創(chuàng)建img標(biāo)簽的加載

  • 「事件監(jiān)聽器」:addEventListener

實(shí)現(xiàn)異步的四種方法

????????對于「setTimeout、setInterval、addEventListener」這種異步場景,不需要我們手動實(shí)現(xiàn)異步,直接調(diào)用即可。

????????但是對于「ajax請求」、「node.js中操作數(shù)據(jù)庫這種異步」,就需要我們自己來實(shí)現(xiàn)了~

1、 回調(diào)函數(shù)

在微任務(wù)隊(duì)列出現(xiàn)之前,JS實(shí)現(xiàn)異步的主要方式就是通過「回調(diào)函數(shù)」

以一個(gè)簡易版的Ajax請求為例,代碼結(jié)構(gòu)如下所示:

function?ajax(obj){
?let?default?=?{
???url:?'...',
???type:'GET',
???async:true,
???contentType:?'application/json',
???success:function(){}
????};

?for?(let?key?in?obj)?{
????????defaultParam[key]?=?obj[key];
????}

????let?xhr;
????if?(window.XMLHttpRequest)?{
????????xhr?=?new?XMLHttpRequest();
????}?else?{
????????xhr?=?new?ActiveXObject('Microsoft.XMLHTTP');
????}
????
????xhr.open(defaultParam.type,?defaultParam.url+'?'+dataStr,?defaultParam.async);
????xhr.send();
????xhr.onreadystatechange?=?function?(){
????????if?(xhr.readyState?===?4){
????????????if(xhr.status?===?200){
????????????????let?result?=?JSON.parse(xhr.responseText);
????????????????//?在此處調(diào)用回調(diào)函數(shù)
????????????????defaultParam.success(result);
????????????}
????????}
????}
}

我們在業(yè)務(wù)代碼里可以這樣調(diào)用「ajax請求」

ajax({
???url:'#',
???type:GET,
???success:function(e){
????//?回調(diào)函數(shù)里就是對請求結(jié)果的處理
???}
});

????????「ajax請求」中的success方法就是一個(gè)回調(diào)函數(shù),回調(diào)函數(shù)中執(zhí)行的是我們請求成功之后要做的進(jìn)一步操作。

????????這樣就初步實(shí)現(xiàn)了異步,但是回調(diào)函數(shù)有一個(gè)非常嚴(yán)重的缺點(diǎn),那就是「回調(diào)地獄」的問題。

????????大家可以試想一下,如果我們在回調(diào)函數(shù)里再發(fā)起一個(gè)ajax請求呢?那豈不是要在success函數(shù)里繼續(xù)寫一個(gè)ajax請求?那如果需要多級嵌套發(fā)起ajax請求呢?豈不是需要多級嵌套?

如果嵌套的層級很深的話,我們的代碼結(jié)構(gòu)可能就會變成這樣:

js 異步,前端,javascript,okhttp,開發(fā)語言

????????因此,為了解決回調(diào)地獄的問題,提出了「promise」「async/await」、「generator」的概念。

2、Promise

「Promise」作為典型的微任務(wù)之一,它的出現(xiàn)可以使JS達(dá)到異步執(zhí)行的效果。

一個(gè)「Promise函數(shù)」的結(jié)構(gòu)如下列代碼如下:

const?promise?=?new?Promise((resolve,?reject)?=>?{
?resolve('a');
});
promise
????.then((arg)?=>?{?console.log(`執(zhí)行resolve,參數(shù)是${arg}`)?})
????.catch((arg)?=>?{?console.log(`執(zhí)行reject,參數(shù)是${arg}`)?})
????.finally(()?=>?{?console.log('結(jié)束promise')?});

????????如果我們需要嵌套執(zhí)行異步代碼,相比于回調(diào)函數(shù)來說,「Promise」的執(zhí)行方式如下列代碼所示:

const?promise?=?new?Promise((resolve,?reject)?=>?{
?resolve(1);
});
promise.then((value)?=>?{
?????console.log(value);
?????return?value?*?2;
????}).then((value)?=>?{
?????console.log(value);
?????return?value?*?2;
????}).then((value)?=>?{
????console.log(value);
????}).catch((err)?=>?{
??console.log(err);
????});

即通過then來實(shí)現(xiàn)多級嵌套(「鏈?zhǔn)秸{(diào)用」),這看起來是不是就比回調(diào)函數(shù)舒服多了~

每個(gè)「Promise」都會經(jīng)歷的生命周期是:

  • 進(jìn)行中(pending)?:此時(shí)代碼執(zhí)行尚未結(jié)束,所以也叫未處理的(unsettled)

    已處理(settled)?:異步代碼已執(zhí)行結(jié)束 已處理的代碼會進(jìn)入兩種狀態(tài)中的一種:
    • 已拒絕(rejected):遇到錯(cuò)誤,異步代碼執(zhí)行失敗 ,由reject()觸發(fā)

    • 已完成(fulfilled):表明異步代碼執(zhí)行成功,由resolve()觸發(fā)

因此,「pending」,「fulfilled」,?「rejected」就是「Promise」中的三種狀態(tài)啦~

????????需要注意的是,在「Promise」中,要么包含resolve()?來表示?「Promise」?的狀態(tài)為fulfilled,要么包含 reject()?來表示「Promise」的狀態(tài)為rejected。

????????不然我們的「Promise」就會一直處于pending的狀態(tài),直至程序崩潰...

除此之外,「Promise」不僅很好的解決了鏈?zhǔn)秸{(diào)用的問題,它還有很多高頻的操作:

  • ·Promise.all(promises)?:接收一個(gè)包含多個(gè)Promise對象的數(shù)組,等待所有都完成時(shí),返回存放它們結(jié)果的數(shù)組。如果任一被拒絕,則立即拋出錯(cuò)誤,其他已完成的結(jié)果會被忽略

  • ·Promise.allSettled(promises)?: 接收一個(gè)包含多個(gè)Promise對象的數(shù)組,等待所有都已完成或者已拒絕時(shí),返回存放它們結(jié)果對象的數(shù)組。每個(gè)結(jié)果對象的結(jié)構(gòu)為{status:'fulfilled' // 或 'rejected', value // 或reason}

  • ·Promise.race(promises)?: 接收一個(gè)包含多個(gè)Promise對象的數(shù)組,等待第一個(gè)有結(jié)果(完成/拒絕)的Promise,并把其result/error作為結(jié)果返回

示例代碼如下所示:

function?getPromises(){
????return?[
????????new?Promise(((resolve,?reject)?=>?setTimeout(()?=>?resolve(1),?1000))),
????????new?Promise(((resolve,?reject)?=>?setTimeout(()?=>?reject(new?Error('2')),?2000))),
????????new?Promise(((resolve,?reject)?=>?setTimeout(()?=>?resolve(3),?3000))),
????];
}

Promise.all(getPromises()).then(console.log);
Promise.allSettled(getPromises()).then(console.log);
Promise.race(getPromises()).then(console.log);

打印結(jié)果為:

js 異步,前端,javascript,okhttp,開發(fā)語言

js 異步,前端,javascript,okhttp,開發(fā)語言

js 異步,前端,javascript,okhttp,開發(fā)語言

3、Generator

????????「generator」是ES6提出的一種異步編程的方案。因?yàn)槭謩觿?chuàng)建一個(gè)iterator十分麻煩,因此ES6推出了「generator」,用于更方便的創(chuàng)建iterator。

????????也就是說,「generator」就是一個(gè)返回值為iterator對象的函數(shù)。

在講「generator」之前,我們先來看看iterator是什么:

?

iterator中文名叫「迭代器」。它為js中各種不同的數(shù)據(jù)結(jié)構(gòu)(Object、Array、Set、Map)提供統(tǒng)一的訪問機(jī)制。
任何數(shù)據(jù)結(jié)構(gòu)只要部署iterator接口,就可以完成遍歷操作。
因此iterator也是一種對象,不過相比于普通對象來說,它有著專為迭代而設(shè)計(jì)的接口。

?

我們通過一個(gè)例子來看看generator的特征:

function*?createIterator()?{
??yield?1;
??yield?2;
??yield?3;
}
//?generators可以像正常函數(shù)一樣被調(diào)用,不同的是會返回一個(gè)?iterator
let?iterator?=?createIterator();
console.log(iterator.next().value);?//?1
console.log(iterator.next().value);?//?2
console.log(iterator.next().value);?//?3

形式上,「generator」?函數(shù)是一個(gè)普通函數(shù),但是有兩個(gè)特征:

  • ·function關(guān)鍵字與函數(shù)名之間有一個(gè)星號

  • ·函數(shù)體內(nèi)部使用yield語句,定義不同的內(nèi)部狀態(tài)

????????在普通函數(shù)中,我們想要一個(gè)函數(shù)最終的執(zhí)行結(jié)果,一般都是return出來,或者以return作為結(jié)束函數(shù)的標(biāo)準(zhǔn)。運(yùn)行函數(shù)時(shí)也不能被打斷,期間也不能從外部再傳入值到函數(shù)體內(nèi)。

????????但在「generator」中,就打破了這幾點(diǎn),所以「generator」和普通的函數(shù)完全不同。

????????當(dāng)以function* ?的方式聲明了一個(gè)「generator」生成器時(shí),內(nèi)部是可以有許多狀態(tài)的,以yield進(jìn)行斷點(diǎn)間隔。期間我們執(zhí)行調(diào)用這個(gè)生成的「generator」,他會返回一個(gè)遍歷器對象,用這個(gè)對象上的方法,實(shí)現(xiàn)獲得一個(gè)yield后面輸出的結(jié)果。

function*?generator()?{
????yield?1
????yield?2
};
let?iterator?=?generator();
iterator.next()??//?{value:?1,?done:?false}
iterator.next()??//?{value:?2,?done:?false}
iterator.next()??//?{value:?undefined,?done:?true}

4、 async/await

最后我們來講講「async/await」,終于講到這兒了?。?!

「async/await」是ES7提出的關(guān)于異步的終極解決方案。我看網(wǎng)上關(guān)于「async/await」是誰的語法糖這塊有兩個(gè)版本:

  • 第一個(gè)版本說「async/await」是Generator的語法糖

  • 第二個(gè)版本說「async/await」是Promise的語法糖

其實(shí),這兩種說法都沒有錯(cuò)。

「關(guān)于async/await是Generator的語法糖:」

????????所謂generator語法糖,表明的就是「aysnc/await」實(shí)現(xiàn)的就是generator實(shí)現(xiàn)的功能。但是「async/await」比generator要好用。因?yàn)間enerator執(zhí)行yield設(shè)下的斷點(diǎn)采用的方式就是不斷的調(diào)用iterator方法,這是個(gè)手動調(diào)用的過程。

????????而async配合await得到的就是斷點(diǎn)執(zhí)行后的結(jié)果。因此「async/await」比generator使用更普遍。

「關(guān)于async/await是Promise的語法糖:」

如果不使用「async/await」的話,Promise就需要通過鏈?zhǔn)秸{(diào)用來依次執(zhí)行then之后的代碼:

function?counter(n){
    return?new?Promise((resolve,?reject)?=>?{?
???    ?resolve(n?+?1);
????});
}

function?adder(a,?b){
????return?new?Promise((resolve,?reject)?=>?{?
??    ??resolve(a?+?b);
????});
}

function?delay(a){
????return?new?Promise((resolve,?reject)?=>?{?
??    ??setTimeout(()?=>?resolve(a),?1000);
????});
}
//?鏈?zhǔn)秸{(diào)用寫法
function?callAll(){
????counter(1)
???????.then((val)?=>?adder(val,?3))
???????.then((val)?=>?delay(val))
???????.then(console.log);
}
callAll();//5

雖然相比于回調(diào)地獄來說,鏈?zhǔn)秸{(diào)用確實(shí)順眼多了。但是其呈現(xiàn)仍然略繁瑣了一些。

「async/await的出現(xiàn),就使得我們可以通過同步代碼來達(dá)到異步的效果」

async?function?callAll(){
???const?count?=?await?counter(1);
???const?sum?=?await?adder(count,?3);
???console.log(await?delay(sum));
}
callAll();//?5

由此可見,「Promise搭配async/await的使用才是正解!」文章來源地址http://www.zghlxwxcb.cn/news/detail-802460.html

到了這里,關(guān)于詳解JS的四種異步解決方案!的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Selenium登錄網(wǎng)頁時(shí),不定時(shí)出現(xiàn)異常彈窗的四種解決方案

    以下是一個(gè)簡單的偽代碼示例,展示了如何加入異常判斷并重新登錄: 在上述示例中,使用了 login() 函數(shù)進(jìn)行登錄操作,并根據(jù)返回值判斷登錄是否成功。然后,使用 check_usbkey_matching() 函數(shù)檢查當(dāng)前用戶與USBKEY是否匹配,并根據(jù)返回值判斷是否需要重新登錄。 如果檢測到當(dāng)

    2024年04月25日
    瀏覽(27)
  • 解決VS中scanf()函數(shù)報(bào)錯(cuò)問題的四種方案(詳細(xì))

    解決VS中scanf()函數(shù)報(bào)錯(cuò)問題的四種方案(詳細(xì))

    ?scanf函數(shù)在VS中報(bào)錯(cuò)的主要原因是 scanf被認(rèn)為不安全而被編譯器默認(rèn)設(shè)置為禁用。 那么如何解決這個(gè)問題呢 法一: 僅將函數(shù) scanf 替換為 scanf_s 即可,其他語法不變。但scanf_s函數(shù)并不是C語言函數(shù)庫里的標(biāo)準(zhǔn)函數(shù),而是VS編譯器所提供的函數(shù),所以并不推薦用這種方法來解決

    2024年02月02日
    瀏覽(16)
  • Node:解決Error: error:0308010C:digital envelope routines::unsupported的四種解決方案

    ??????? 主要是因?yàn)?nodeJs V17 版本發(fā)布了 OpenSSL3.0 對算法和秘鑰大小增加了更為嚴(yán)格的限制,nodeJs v17 之前版本沒影響,但 V17 和之后版本會出現(xiàn)這個(gè)錯(cuò)誤。 我的node版本是v18+ 報(bào)錯(cuò)詳細(xì)信息: ?? 方案1:打開IDEA 終端,直接輸入 Linux Mac OS: Windows: 方案2:打開IDEA 終端,直

    2024年04月13日
    瀏覽(25)
  • js跨域的解決方案

    js跨域的解決方案

    指的是瀏覽器不能執(zhí)行其他網(wǎng)站的腳本,簡單來說是瀏覽器同源政策的限制,瀏覽器針對于ajax的限制。 同源政策 兩個(gè)頁面擁有相同的 協(xié)議,端口,域名 就是同源,如果有一個(gè)不相同就是不同源。 同源政策產(chǎn)生的目的 保護(hù)用戶信息安全,防止一些網(wǎng)站盜取用戶信息。 常見

    2024年02月10日
    瀏覽(778)
  • 最簡單的大屏適配解決方案---autofit.js

    最簡單的大屏適配解決方案---autofit.js

    在工作開發(fā)當(dāng)中,我們避免不了要去做大屏。那么做大屏其實(shí)最難的點(diǎn)和最核心的問題就是適配, 下面為大家介紹最好用的大屏解決方案——autofit.js。 效果圖展示,可根據(jù)窗口大小進(jìn)行自動適配。 使用方法: 1.npm下載: 2.項(xiàng)目中引入使用: 3.init()初始化加載:注意一定要

    2024年02月08日
    瀏覽(24)
  • Three.js深度沖突(模型閃爍)與解決方案

    Three.js深度沖突(模型閃爍)與解決方案

    下面代碼創(chuàng)建兩個(gè)重合的矩形平面Mesh,通過瀏覽器預(yù)覽,當(dāng)你旋轉(zhuǎn)三維場景的時(shí)候,你會發(fā)現(xiàn)模型渲染的時(shí)候產(chǎn)生閃爍。 這種現(xiàn)象,主要是兩個(gè)Mesh重合,電腦GPU分不清誰在前誰在后,這種現(xiàn)象,可以稱為深度沖突 Z-fighting 。 look 適當(dāng)偏移,解決深度沖突,偏移尺寸相對模型

    2024年02月17日
    瀏覽(13)
  • [javascript核心-09] 徹底解決js中的類型檢測方案

    typeof 基于數(shù)據(jù)類型的值(二進(jìn)制)進(jìn)行檢測 返回結(jié)果為字符串 typeof NaN 結(jié)果為 number typeof null 結(jié)果為 Object .對象存儲以 000 開頭,而 null 也是如此。 typeof 不能細(xì)分對象,結(jié)果都是 Object typeof function(){} 結(jié)果為 function instanceof 檢測某個(gè)構(gòu)造函數(shù)是否出現(xiàn)在某實(shí)例的原型鏈上 返回結(jié)

    2024年02月16日
    瀏覽(24)
  • js之刪除對象屬性的三種方法 & 判斷對象中是否有某一屬性的四種方法

    js之刪除對象屬性的三種方法 判斷對象中是否有某一屬性的四種方法 示例 1、基礎(chǔ)版 2、進(jìn)階版 1、刪除一個(gè)對象上的屬性 1.1、delete 語法 delete 對象.屬性名 1.2、es6之解構(gòu)賦值 1.3、es6之反射 語法 Reflect.deleteProperty(對象,屬性名) 2、判斷對象中是否有某一屬性的四種方法 2.1、

    2024年02月13日
    瀏覽(21)
  • Vue.js WebSocket 整合指南:實(shí)時(shí)通信的完美解決方案

    WebSocket是一種在Web應(yīng)用程序中實(shí)現(xiàn)雙向通信的通信協(xié)議,它允許客戶端和服務(wù)器之間建立持久的、低延遲的連接,以實(shí)現(xiàn)實(shí)時(shí)數(shù)據(jù)傳輸。相比傳統(tǒng)的HTTP請求,WebSocket更適合需要實(shí)時(shí)性和交互性的應(yīng)用程序。 WebSocket解決了傳統(tǒng)HTTP請求的一些限制,例如: 實(shí)時(shí)性: 傳統(tǒng)HTTP請求需

    2024年02月04日
    瀏覽(23)
  • Node.js16.15.1的一個(gè)報(bào)錯(cuò)及解決方案

    Node.js16.15.1的一個(gè)報(bào)錯(cuò)及解決方案

    最近在進(jìn)行Node.js的下載安裝和環(huán)境的配置,在官網(wǎng)上下載了LTS版本16.15.1,沒想到在后續(xù)的使用中出現(xiàn)一種報(bào)錯(cuò)。 例如,在命令提示符窗口中輸入 npm -v 想要查看npm的版本號: 關(guān)于這個(gè)報(bào)錯(cuò),我一開始的解決方案是將Node.js安裝目錄下的 npm.cmd 文件第12行的 prefix -g 改成 prefix

    2023年04月08日
    瀏覽(23)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包