async function

2021-9-24    前端達(dá)人

這篇文章多看幾遍加深理解

async function 聲明定義了一個(gè)異步函數(shù),它返回一個(gè)AsyncFunction對(duì)象。異步函數(shù) 是指通過(guò) 事件循環(huán)(event loop) 異步執(zhí)行的函數(shù),通過(guò)返回一個(gè)隱式的 Promise 作為其結(jié)果。使用異步函數(shù)的代碼的語(yǔ)法和結(jié)構(gòu)更像使用標(biāo)準(zhǔn)同步功能。(The async function declaration defines an asynchronous function, which returns an AsyncFunction object. An asynchronous function is a function which operates asynchronously via the event loop, using an implicit Promise to return its result. But the syntax and structure of your code using async functions is much more like using standard synchronous functions.

語(yǔ)法

async function name([param[, param[, ... param]]]) { statements } 
  • 1

參數(shù)

  • name:函數(shù)名稱
  • param:要傳遞給函數(shù)的參數(shù)。
  • statements:函數(shù)體語(yǔ)句。

返回值:返回一個(gè)promise對(duì)象,將返回異步函數(shù)返回的值(如果異步函數(shù)是resolved則返回resolved的值;如果拋出異常,則rejected從異步函數(shù)中拋出的異常)。(A Promise which will be resolved with the value returned by the async function, or rejected with an uncaught exception thrown from within the async function.)

異步函數(shù)可以包含await表達(dá)式,該表達(dá)式暫停異步函數(shù)的執(zhí)行 并等待 Promise的執(zhí)行結(jié)果返回,結(jié)果返回后就恢復(fù)異步函數(shù)的執(zhí)行。

await 關(guān)鍵字只在異步函數(shù)(async functions)內(nèi)有效。如果在異步函數(shù)外使用它,會(huì)拋出語(yǔ)法錯(cuò)誤。
當(dāng)異步函數(shù)暫停時(shí),它調(diào)用的函數(shù)仍會(huì)繼續(xù)執(zhí)行。

舉例一:

function resolveAfter5Seconds() { return new Promise(resolve => { setTimeout(() => { resolve('resolved'); }, 5000); }); } async function asyncCall() { console.log('calling'); let result = await resolveAfter5Seconds(); console.log(result); // 5s之后輸出結(jié)果 } asyncCall(); //返回的是一個(gè)promise對(duì)象 // console.log(asyncCall()); // Promise { <pending> } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

運(yùn)行效果:
在這里插入圖片描述
舉例二:

let resolveAfter6Second = function () { console.log('start slow promise'); return new Promise(resolve => { setTimeout(() => { resolve('slow'); console.log('slow promise is done'); }, 6000); }) } let resolveAfter4Second = function () { console.log('start fast promise'); return new Promise(resolve => { setTimeout(() => { resolve('fast'); console.log('fast promise is done'); }, 4000); }) } let sequentialStart = async function () { console.log('sequential start'); const slow = await resolveAfter6Second(); console.log(slow); const fast = await resolveAfter4Second(); console.log(fast); } sequentialStart() //立即輸出 // sequential start // start slow promise //再過(guò)6秒后輸出 // slow promise is done // slow // start fast promise //再過(guò)4秒后輸出 // fast promise is done // fast 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

運(yùn)行效果:
在這里插入圖片描述
換一種await的寫(xiě)法,結(jié)果完全不同:兩個(gè)計(jì)時(shí)器被同時(shí)創(chuàng)建

let resolveAfter6Seconds = function () { console.log('start slow promise'); return new Promise(resolve => { setTimeout(() => { resolve('slow'); console.log('slow promise is done'); }, 6000); }) } let resolveAfter4Seconds = function () { console.log('start fast promise'); return new Promise(resolve => { setTimeout(() => { resolve('fast'); console.log('fast promise is done'); }, 4000); }) } let concurrentStart = async function () { console.log('concurrent start'); let slow = resolveAfter6Seconds(); let fast = resolveAfter4Seconds(); console.log(await slow); console.log(await fast); } setTimeout(() => { concurrentStart(); }, 2000); //2秒后執(zhí)行 // concurrent start // start slow promise // start fast promise //再過(guò)4秒后執(zhí)行 // fast promise is done //再過(guò)2秒后執(zhí)行 // slow promise is done // slow // fast 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

運(yùn)行效果:
在這里插入圖片描述
在 concurrentStart 中,兩個(gè)計(jì)時(shí)器被同時(shí)創(chuàng)建,接著執(zhí)行await。等待的是 promise的resolve回調(diào),resolve后面的代碼( console.log(‘fast promise is done’);)會(huì)繼續(xù)執(zhí)行。
這兩個(gè)計(jì)時(shí)器同時(shí)運(yùn)行。但是 await 仍舊是順序執(zhí)行的,第二個(gè) await 還是得等待第一個(gè)執(zhí)行完。在這個(gè)例子中,這使得先運(yùn)行結(jié)束的輸出出現(xiàn)在最慢的輸出之后。
也可以把 concurrentStart 改寫(xiě)成如下,運(yùn)行效果一樣:

let resolveAfter6Seconds = function () { console.log('start slow promise'); return new Promise(resolve => { setTimeout(() => { resolve('slow'); console.log('slow promise is done'); }, 6000); }) } let resolveAfter4Seconds = function () { console.log('start fast promise'); return new Promise(resolve => { setTimeout(() => { resolve('fast'); console.log('fast promise is done'); }, 4000); }) } let concurrentPromise = async function () { console.log('concurrent start'); return Promise.all([resolveAfter6Seconds(), resolveAfter4Seconds()]).then((messages) => { console.log(messages[0]); // slow console.log(messages[1]); // fast }); } setTimeout(() => { concurrentPromise(); }, 2000); //2秒后輸出 // concurrent start // start slow promise // start fast promise //再過(guò)6秒后輸出 // fast promise is done //再過(guò)2秒后輸出 // slow promise is done // slow // fast 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

并行執(zhí)行兩個(gè)或更多的任務(wù),如下例所示:

let resolveAfter6Seconds = function () { console.log('start slow promise'); return new Promise(resolve => { setTimeout(() => { resolve('slow'); console.log('slow promise is done'); }, 6000); }) } let resolveAfter4Seconds = function () { console.log('start fast promise'); return new Promise(resolve => { setTimeout(() => { resolve('fast'); console.log('fast promise is done'); }, 4000); }) } let parallel = async function () { console.log('start paralel'); await Promise.all([ (async () => console.log(await resolveAfter6Seconds()))(), (async () => console.log(await resolveAfter4Seconds()))() ]); } setTimeout(parallel, 2000); //2秒后輸出 // start paralel // start slow promise // start fast promise //再過(guò)4秒后輸出 // fast promise is done // fast //再過(guò)2秒后輸出 // slow promise is done // slow 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

運(yùn)行效果:
在這里插入圖片描述
如果希望并行執(zhí)行兩個(gè)或更多的任務(wù),你必須像在parallel中一樣使用await Promise.all([job1(), job2()])

也可以把parallel改寫(xiě)成如下,運(yùn)行效果一樣:

let resolveAfter6Seconds = function(){ console.log('start slow promise'); return new Promise(resolve => { setTimeout(() => { resolve('slow'); console.log('slow promise is done'); }, 6000); }); } let resolveAfter4Seconds = function(){ console.log('start fast promise'); return new Promise(resolve =>{ setTimeout(() => { resolve('fast'); console.log('fast promise is done'); }, 4000); }) } let parallelPromise = function(){ console.log('parallelPromise start'); resolveAfter6Seconds().then(msg => console.log(msg)); resolveAfter4Seconds().then(msg => console.log(msg)); } setTimeout(() => { parallelPromise(); }, 2000); //2秒后輸出 // parallelPromise start // start slow promise // start fast promise //再過(guò)4秒后輸出 // fast promise is done // fast //再過(guò)2秒后輸出 // slow promise is done // slow 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

async/await和Promise#then對(duì)比以及錯(cuò)誤處理:
大多數(shù)異步函數(shù)(async functions )也可以使用 Promises函數(shù) 編寫(xiě)。然而,當(dāng)涉及到錯(cuò)誤處理時(shí),異步函數(shù)不太容易出錯(cuò)。
上面例子中的concurrentStart函數(shù)和concurrentPromise函數(shù)在功能上都是等效的。在concurrentStart函數(shù)中,如果任一awaited調(diào)用失敗,它將自動(dòng)捕獲異常,異步函數(shù)執(zhí)行中斷,并通過(guò)隱式返回Promise將錯(cuò)誤傳遞給調(diào)用者。
在Promise例子中這種情況同樣會(huì)發(fā)生,函數(shù)必須負(fù)責(zé)返回一個(gè)捕獲函數(shù)完成的Promise。在concurrentPromise函數(shù)中,這意味著它從Promise.all([]).then()中返回一個(gè)Promise。事實(shí)上,在此示例的先前版本忘記了這樣做!
但是,async函數(shù)仍有可能然可能錯(cuò)誤地忽略錯(cuò)誤。
以parallel異步函數(shù)為例。 如果它沒(méi)有等待await(或 return)Promise.all([])調(diào)用的結(jié)果,則不會(huì)傳播任何錯(cuò)誤。
雖然parallelPromise函數(shù)示例看起來(lái)很簡(jiǎn)單,但它根本不會(huì)處理錯(cuò)誤! 這樣做需要一個(gè)類似于return Promise.all([])處理方式。(詳見(jiàn)

使用async函數(shù)重寫(xiě) promise 鏈

返回 Promise的 API 將會(huì)產(chǎn)生一個(gè) promise 鏈,它將函數(shù)分解成許多部分。例如下面的代碼:

function getProcessedData(url) { return downloadData(url)// returns a promise .catch(e => { return downloadFallbackData(url);// returns a promise }) .then(v => { return processDataInWorker(v);// returns a promise }) } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

可以重寫(xiě)為單個(gè)async函數(shù):

async function getProcessedData(url) { let v; try { v = await downloadData(url); } catch (e) { v = await downloadFallbackData(); } return processDataInWorker(v); } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

在上述示例中,return 語(yǔ)句中沒(méi)有 await 操作符,因?yàn)?async function 的返回值將被隱式地傳遞給 Promise.resolve。

return await promiseValue; 與 return promiseValue;的比較

返回值隱式的傳遞給Promise.resolve,并不意味著return await promiseValue;,只是在功能上等同于返回return promiseValue;
重寫(xiě)的上面代碼,在processDataInWorker拋出異常時(shí)返回null:

async function getProcessedData(url) { let v; try { v = await downloadData(url); } catch(e) { v = await downloadFallbackData(url); } try { return await processDataInWorker(v); // 注意 `return await` 和單獨(dú) `return` 的比較 } catch (e) { return null; } } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

簡(jiǎn)單地寫(xiě)上return processDataInworker(v);將導(dǎo)致在processDataInWorker(v)出錯(cuò)時(shí)function返回值為Promise而不是返回null。

return foo;return await foo;有一些細(xì)微的差異:
return foo;不管foo是promise還是rejects都將會(huì)直接返回foo。相反地,如果foo是一個(gè)Promise,return await foo;將等待foo執(zhí)行(resolve)或拒絕(reject),如果是拒絕,將會(huì)在返回前拋出異常。


















藍(lán)藍(lán)設(shè)計(jì)建立了UI設(shè)計(jì)分享群,每天會(huì)分享國(guó)內(nèi)外的一些優(yōu)秀設(shè)計(jì),如果有興趣的話,可以進(jìn)入一起成長(zhǎng)學(xué)習(xí),請(qǐng)掃碼藍(lán)小助,報(bào)下信息,藍(lán)小助會(huì)請(qǐng)您入群。歡迎您加入噢~~希望得到建議咨詢、商務(wù)合作,也請(qǐng)與我們聯(lián)系。

分享此文一切功德,皆悉回向給文章原作者及眾讀者.

轉(zhuǎn)自:csdn
免責(zé)聲明:藍(lán)藍(lán)設(shè)計(jì)尊重原作者,文章的版權(quán)歸原作者。如涉及版權(quán)問(wèn)題,請(qǐng)及時(shí)與我們?nèi)〉寐?lián)系,我們立即更正或刪除。

藍(lán)藍(lán)設(shè)計(jì)www.bouu.cn )是一家專注而深入的界面設(shè)計(jì)公司,為期望卓越的國(guó)內(nèi)外企業(yè)提供卓越的UI界面設(shè)計(jì)、BS界面設(shè)計(jì) 、 cs界面設(shè)計(jì) 、 ipad界面設(shè)計(jì) 、 包裝設(shè)計(jì) 、 圖標(biāo)定制 、 用戶體驗(yàn) 、交互設(shè)計(jì)、 網(wǎng)站建設(shè) 平面設(shè)計(jì)服務(wù)


分享本文至:

日歷

鏈接

個(gè)人資料

存檔