公交车上荫蒂添的好舒服的电影-公用玩物(np双xing总受)-公用小荡货芊芊-公与妇仑乱hd-攻把受做哭边走边肉楼梯play-古装一级淫片a免费播放口

LOGO OA教程 ERP教程 模切知識交流 PMS教程 CRM教程 開發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

詳解JavaScript異步編程之a(chǎn)sync和await

admin
2024年4月1日 15:5 本文熱度 1541

經(jīng)過了Generator的過渡之后異步代碼同步化的需求逐漸成為了主流需求,雖然Generator函數(shù)能夠?qū)崿F(xiàn)異步編程,但實際上我們很少用它來實現(xiàn)異步,因為在ES7版本中得到了提案,并在ES8版本中進⾏了實現(xiàn)的 async 函數(shù)對Generator函數(shù)的流程又做了一層封裝,定義了全新的異步控制流程,使得異步方案使用更加方便。


01
介紹


async function foo(){
 await ...
 await ...
}
foo()

async/await的代碼結(jié)構(gòu)的編寫⽅式與Generator函數(shù)結(jié)構(gòu)很相似,async就相當(dāng)于那個(*),await就相當(dāng)于yield。提案中規(guī)定了可以使⽤async修飾⼀個函數(shù),這樣就能在該函數(shù)的直接⼦作⽤域中,使⽤await來⾃動的控制函數(shù)的流程,await 右側(cè)可以編寫任何變量或?qū)ο螅?dāng)右側(cè)是普通對象的時候函數(shù)會⾃動返回右側(cè)的結(jié)果并向下執(zhí)⾏,⽽當(dāng)await右側(cè)為Promise對象時,如果Promise對象狀態(tài)沒有變成完成,函數(shù)就會掛起等待,直到Promise對象變成fulfilled,程序再向下執(zhí)⾏,并且Promise的值會⾃動返回給await左側(cè)的變量中。async和await需要成對出現(xiàn),async可以單獨修飾函數(shù),但是await只能在被async修飾的函數(shù)中使⽤。


有了await和async就相當(dāng)于使⽤了⾃帶執(zhí)⾏函數(shù)的Generator函數(shù),這樣我們就不再需要單獨針對Generator函數(shù)進⾏開發(fā)了,所以async和await逐漸成為主流異步流程控制的終極解決⽅案。⽽Generator慢慢淡出了業(yè)務(wù)開發(fā)者的舞臺,不過Generator函數(shù)成為了向下兼容過渡期版本瀏覽器的候補實現(xiàn)⽅式,雖然在現(xiàn)今的⼤部分項⽬業(yè)務(wù)中使⽤Generator函數(shù)的場景⾮常的少,但是如果查看腳⼿架項⽬中通過babel構(gòu)建的JavaScript⽣產(chǎn)代碼,我們還是能⼤量的發(fā)現(xiàn)Generator的應(yīng)⽤的,它的作⽤就是為了兼容不⽀持async和await的瀏覽器。


02
介紹async


async的英文意思是異步,當(dāng)函數(shù)前面有async關(guān)鍵字并且該函數(shù)有返回值時,函數(shù)執(zhí)行成功,函數(shù)就會調(diào)用Promise.resove()并隱式的返回一個Promise對象;如果函數(shù)執(zhí)行失敗就會調(diào)用Promise.reject()并返回一個Promise對象。

async function foo(){
  return 1
}
let res = foo()
console.log(res)

根據(jù)控制臺結(jié)果我們發(fā)現(xiàn)其實async修飾的函數(shù),本身就是⼀個Promise對象,雖然我們在函數(shù)中return的值是1,是使⽤了async修飾之后,這個函數(shù)運⾏時并沒有直接返回1,⽽是返回了⼀個值為1的Promise對象。


async函數(shù)中如果有異步操作會進行等待,但是async函數(shù)本身會馬上返回,不會阻塞當(dāng)前線程。async函數(shù)被調(diào)用不會阻塞界面渲染,內(nèi)部由await關(guān)鍵字修飾異步過程,會阻塞等待異步任務(wù)的完成再返回。

如果在函數(shù)中return一個直接量,async會把這個直接量通過Promise.resolve(直接量) 封裝成 Promise 對象 ,如果沒有返回值,相當(dāng)于返回了Promise.resolve(undefined)。

我們可以通過Promise.then()回調(diào)得到async函數(shù)的返回值,因為該函數(shù)返回的是Promise對象。

async function foo(){
  return 1
}
let res = foo()
console.log(res)

foo().then((res) => {
  console.log('res的值是', res)
})

只有async函數(shù)內(nèi)部的異步操作執(zhí)行完,才會執(zhí)行then方法指定的回調(diào)函數(shù)。


看下面代碼:

async function foo(){
    console.log(3)
    return 1;
}
console.log(1)
foo()
console.log(2)

通過控制臺看到打印順序為1、3、2。按照Promise對象的執(zhí)⾏流程function被async修飾之后它本身應(yīng)該變成異步函數(shù),那么它應(yīng)該在1和2輸出完畢之后再輸出3,但是結(jié)果卻出⼈意料,這是為什么呢?

我們回想一下Promise函數(shù)的結(jié)構(gòu)。

new Promise(function(){
    
}).then(function(){

})

在介紹Promise對象時,我們知道new Promise時的function是同步流程,而then()是異步的,這也就不難解釋為什么輸出結(jié)果是1、3、2了。


03
介紹await


await的英文意思是等待,等待的是一個表達式,這個表達式的計算結(jié)果是 Promise 對象或者其它值,得到resolve的值作為await表達式的運算結(jié)果。

因為 async 函數(shù)返回一個 Promise 對象,所以 await 可以用于等待一個 async 函數(shù)的返回值,這也可以說是 await 在等 async 函數(shù),實際上它等待的是一個返回值。await 不僅僅用于等 Promise 對象,它可以等任意表達式的結(jié)果。


await 表達式的運算結(jié)果取決于它等的東西。如果它等到的不是一個 Promise 對象,相當(dāng)于 await Promise.resolve(...),那 await 表達式的運算結(jié)果就是它等到的東西。

如果它等到的是一個 Promise 對象,它會阻塞后面的代碼,等著 Promise 對象 resolve,然后得到 resolve 的值,作為 await 表達式的運算結(jié)果。

依然以上面的代碼為例,稍加改造。

async function foo(){
  console.log(3);
  var a = await 4;
  console.log(a);
  return 1;
}

console.log(1)
foo()
console.log(2)

通過控制臺我們可以看到打印順序為1->3->2->4。可以看到await 4表達式會將4作為其運算結(jié)果賦值給a,并且await會阻塞后面的console.log(a)的執(zhí)行,所以最后才會打印出4,這就是 await 必須用在 async 函數(shù)中的原因。

我們將上面的函數(shù)翻譯⼀下,由于async修飾的函數(shù)會被解釋成Promise對象,所以我們可以將其翻譯成如下結(jié)構(gòu):

console.log(1)
new Promise(function(resolve){
    console.log(3)
    resolve(4)
}).then(function(a){
    console.log(a)
})
console.log(2)

看到這個Promise對象我們就明白了,由于初始化的回調(diào)是同步的所以1,3,2都是同步代碼,⽽4是在resolve中傳⼊的,then代表異步回調(diào)所以4應(yīng)該最后輸出。

綜上所述,async函數(shù)中有⼀個最大的特點,就是第⼀個await會作為分⽔嶺⼀般的存在,在第⼀個await的右側(cè)和上⾯的代碼,全部是同步代碼區(qū)域相當(dāng)于new Promise的回調(diào),第⼀個await的左側(cè)和下⾯的代碼,就變成了異步代碼區(qū)域相當(dāng)于then的回調(diào)。


04
await的優(yōu)勢


假設(shè)一個業(yè)務(wù),分多個步驟完成,每個步驟都是異步的,而且依賴于上一個步驟的結(jié)果。在過去的編程中JavaScript的主要異步處理⽅式,是采⽤回調(diào)函數(shù)的⽅式來進⾏處理,想要保證n個步驟的異步編程有序進⾏,會出現(xiàn)如下的代碼。

setTimeout(function(){
  //第⼀秒后執(zhí)⾏的邏輯
  console.log('第⼀秒之后發(fā)⽣的事情')
  setTimeout(function(){
    //第⼆秒后執(zhí)⾏的邏輯
    console.log('第⼆秒之后發(fā)⽣的事情')
      setTimeout(function(){
      //第三秒后執(zhí)⾏的邏輯
      console.log('第三秒之后發(fā)⽣的事情')
    },1000)
  },1000)
},1000)

雖然可以Promise 通過 then 鏈來解決多層回調(diào)的問題,但是現(xiàn)在有了async/await我們可使用它來進一步優(yōu)化上面的代碼。

// 假設(shè)起始值為1,每個步驟都是異步的,而且依賴于上一個步驟的計算結(jié)果,且每間隔一秒打印結(jié)果
function runTask(n) {
    return new Promise(resolve => {
        setTimeout(() => resolve(n + 1), 1000);
    });
}

function task1(n) {
    console.log(`step1 with ${n}`);
    return runTask(n);
}

function task2(n) {
    console.log(`step2 with ${n}`);
    return runTask(n);
}

function task3(n) {
    console.log(`step3 with ${n}`);
    return runTask(n);
}

用 Promise 方式來實現(xiàn)這三個步驟。

function run() {
    const sum1 = 1;
    task1(sum1)
        .then(sum2 => task2(time2))
        .then(time3 => task3(time3))
        .then(result => {
            console.log(result) // 4
        });
}
run();

如果用 async/await 來實現(xiàn)如下。

async function run() {
    const sum1 = 1;
    const sum2 = await task1(sum1);
    const sum3 = await task2(sum2);
    const result = await task3(sum3);
    console.log(`result is ${result}`); // result is 4
}

run();

現(xiàn)在我們可以使⽤如上的⽅式來進⾏流程控制,不再需要依賴自己定義的流程控制器函數(shù)來進⾏分步執(zhí)⾏,這⼀切的核⼼起源都是Promise對象的規(guī)則定義開始的。使用async/await結(jié)果和之前的 Promise 實現(xiàn)是一樣的,但是這個代碼看起來是不是清晰得多,幾乎跟同步代碼一樣。


05
注意事項


1、await只能用在async函數(shù)之中,也就是說await必須和async一起使用,反之,async可以單獨只用。


2、await后面跟著是一個Promise對象,會等待Promise返回結(jié)果了,再繼續(xù)執(zhí)行后面的代碼。

const timer = n => {
    return new Promise(function(resolve, reject) {
        setTimeout(function() {
            console.log('1')
            resolve();
        }, n);
    })
};
const run = async () => {
    await timer(3000);
    console.log('2');
};
run()
// 等待3s之后,分別打印出1、2


3、await后面跟著的是一個數(shù)值或者是字符串等數(shù)據(jù)類型的值,則直接返回該值。


4、await后面跟著的是定時器,不會等待定時器里面的代碼執(zhí)行完,而是直接執(zhí)行后面的代碼,然后再執(zhí)行定時器中的代碼。

const run = async () => {
    console.log(1)
    await setTimeout(() => {
        console.log(2)
    }, 1000);
    console.log(3);
};
run()
// 1 -> 3 -> 2


5、可以直接用標(biāo)準(zhǔn)的try...catch...語法捕捉錯誤。

async function asyncFunction() {
    throw new Error('Something went wrong');
}

const run = async() => {
    try {
        await asyncFunction();
    } catch (error) {
        console.error('Caught an error:', error);
    }
}
run()


06
總結(jié)


從回調(diào)地獄到Promise的鏈?zhǔn)秸{(diào)⽤到Generator函數(shù)的分步執(zhí)⾏再到async和await的⾃動異步代碼同步化機制,經(jīng)歷了很多個年頭,所以⾯試中為什么經(jīng)常問到Promise,并且重點沿著Promise對象深⼊的挖掘去問你各種問題,主要是考察程序員對Promise對象本身以及他的發(fā)展歷程是否有深⼊的了解,同時也是在考察⾯試者對JavaScript的事件循環(huán)系統(tǒng)和異步編程的基本功是否⾜夠的扎實。Promise和事件循環(huán)系統(tǒng)并不是JavaScript中的⾼級知識,⽽是真正的基礎(chǔ)知識,所以所有⼈想要在⾏業(yè)中更好的發(fā)展下去,這些知識都是必備基礎(chǔ),必須扎實掌握。


該文章在 2024/4/1 15:05:16 編輯過
關(guān)鍵字查詢
相關(guān)文章
正在查詢...
點晴ERP是一款針對中小制造業(yè)的專業(yè)生產(chǎn)管理軟件系統(tǒng),系統(tǒng)成熟度和易用性得到了國內(nèi)大量中小企業(yè)的青睞。
點晴PMS碼頭管理系統(tǒng)主要針對港口碼頭集裝箱與散貨日常運作、調(diào)度、堆場、車隊、財務(wù)費用、相關(guān)報表等業(yè)務(wù)管理,結(jié)合碼頭的業(yè)務(wù)特點,圍繞調(diào)度、堆場作業(yè)而開發(fā)的。集技術(shù)的先進性、管理的有效性于一體,是物流碼頭及其他港口類企業(yè)的高效ERP管理信息系統(tǒng)。
點晴WMS倉儲管理系統(tǒng)提供了貨物產(chǎn)品管理,銷售管理,采購管理,倉儲管理,倉庫管理,保質(zhì)期管理,貨位管理,庫位管理,生產(chǎn)管理,WMS管理系統(tǒng),標(biāo)簽打印,條形碼,二維碼管理,批號管理軟件。
點晴免費OA是一款軟件和通用服務(wù)都免費,不限功能、不限時間、不限用戶的免費OA協(xié)同辦公管理系統(tǒng)。
Copyright 2010-2025 ClickSun All Rights Reserved

主站蜘蛛池模板: 精品久久久久久无码专区不卡 | 国产成人av第一页 | 国产女人喷浆抽搐高潮 | 国产成人亚洲欧美电影 | 精品国产av无码一区二区三区 | 国产午夜小视频在线 | 国产一级毛片 | 91麻豆国产 | 国产精品福利一区二区久久 | 成a人片在线观看中文漫画 成a人无码午夜电影 | 国产午夜激无码毛片久久hd | ts人妖国产一区 | 国产免费一区二区视频麻豆 | 国产精品重口变态sm在线观看 | 91成人免费观看网站 | 国产精品无码一区二区在线 | 2025国产精品国产精华 | 91情国产l精品国产亚洲区 | 激情无码人妻又粗又大 | 成人无码h免费动漫 | 国产91福利精品免费观看 | 国产交换精品一区二区三区 | 国产成人av片无码免费 | 国产美女裸身无遮挡网站 | 精品动漫无码在线一区二区三区 | 国产精品一国产精品最新章节 | 精品久久福利一区二区 | 国产a一级黄片视频 | 精品高潮呻吟9 | 99久久无码一区人妻久久 | 国产一区二区三区在线电影 | 国产精品另类 | 91亚洲超碰无码中文字幕 | 国产成人涩涩屋视频在线 | av天堂手机版在线观看网站 | 国产午夜激无码av毛片护士 | 国产精品高清一区二区三区不卡 | 精品久久久久久无码中文野结衣 | 韩国无码一区二区三区精品 | 高清无码一区二区三区老色鬼 | 国产品无码一区二区三区在线 |