狠狠色丁香婷婷综合尤物/久久精品综合一区二区三区/中国有色金属学报/国产日韩欧美在线观看 - 国产一区二区三区四区五区tv

LOGO OA教程 ERP教程 模切知識交流 PMS教程 CRM教程 開發文檔 其他文檔  
 
網站管理員

詳解JavaScript異步編程之async和await

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

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


01
介紹


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

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


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


02
介紹async


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

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

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


async函數中如果有異步操作會進行等待,但是async函數本身會馬上返回,不會阻塞當前線程。async函數被調用不會阻塞界面渲染,內部由await關鍵字修飾異步過程,會阻塞等待異步任務的完成再返回。

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

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

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

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

只有async函數內部的異步操作執行完,才會執行then方法指定的回調函數。


看下面代碼:

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

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

我們回想一下Promise函數的結構。

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

})

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


03
介紹await


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

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


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

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

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

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作為其運算結果賦值給a,并且await會阻塞后面的console.log(a)的執行,所以最后才會打印出4,這就是 await 必須用在 async 函數中的原因。

我們將上面的函數翻譯⼀下,由于async修飾的函數會被解釋成Promise對象,所以我們可以將其翻譯成如下結構:

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

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

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


04
await的優勢


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

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

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

// 假設起始值為1,每個步驟都是異步的,而且依賴于上一個步驟的計算結果,且每間隔一秒打印結果
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 方式來實現這三個步驟。

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

如果用 async/await 來實現如下。

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();

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


05
注意事項


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


2、await后面跟著是一個Promise對象,會等待Promise返回結果了,再繼續執行后面的代碼。

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后面跟著的是一個數值或者是字符串等數據類型的值,則直接返回該值。


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

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


5、可以直接用標準的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
總結


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


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