摘要:是一種與協(xié)作的特殊的語(yǔ)法。換句話說(shuō),僅可以運(yùn)行在中。所以將會(huì)進(jìn)行等待,而之后拋出一個(gè)錯(cuò)誤。同時(shí)這也將更為便利。允許在函數(shù)內(nèi)部使用。關(guān)鍵詞確保運(yùn)行時(shí)將會(huì)等待處理完畢,并且如果觸發(fā)了一個(gè)運(yùn)行錯(cuò)誤,運(yùn)行中斷,并在改處類(lèi)似觸發(fā)。
Async函數(shù)“async/await”是一種與“promise”協(xié)作的特殊的語(yǔ)法。它使得異步工作更加容易理解和使用。
我們從async關(guān)鍵詞開(kāi)始,它可以被放置在任何函數(shù)的開(kāi)頭位置,比如:
async function f() { return 1; }
這里的async表示:該函數(shù)將始終返回一個(gè)promise。即使您的代碼沒(méi)有顯式返回一個(gè)promise,在JavaScript運(yùn)行時(shí)也會(huì)自動(dòng)包裝一個(gè)promise,用于返回指定的值。
在這個(gè)例子中,這段代碼將會(huì)返回一個(gè)result為1的promise:
async function f() { return 1; } f().then(alert); // 1
當(dāng)然,我們也可以顯式的返回一個(gè)promise:
async function f() { return Promise.resolve(1); } f().then(alert); // 1
async確保了函數(shù)會(huì)返回一個(gè)promise。挺簡(jiǎn)單的對(duì)吧?接下來(lái),是另一個(gè)關(guān)鍵詞await,僅僅能在async標(biāo)記的函數(shù)中生效。
Await語(yǔ)法說(shuō)明:
//該段代碼僅僅能在 async 標(biāo)記的函數(shù)中生效 let value = await promise;
關(guān)鍵詞await確保JavaScript運(yùn)行時(shí)將會(huì)等待promise執(zhí)行完畢并返回結(jié)果。
下面是一段使用promise并在一秒后返回結(jié)果的例子:
async function f() { let promise = new Promise((resolve, reject) => { setTimeout(() => resolve("done!"), 1000) }); let result = await promise; // 等待至promise獲得結(jié)果 (*) alert(result); // "done!" } f();
該函數(shù)在運(yùn)行至await時(shí),執(zhí)行了“pauses”操作,直至promise執(zhí)行完畢后重新執(zhí)行接下來(lái)的代碼。所以該段代碼將在一秒后顯示“done!”。
讓我們強(qiáng)調(diào)一遍:await將順序使得JavaScript的運(yùn)行時(shí)等待promise執(zhí)行完畢,而后繼續(xù)運(yùn)行余下代碼。等待時(shí)的操作并不會(huì)消耗任何CPU資源,因?yàn)榇藭r(shí)的運(yùn)行時(shí)可以同時(shí)執(zhí)行其他操作:執(zhí)行其他的代碼,處理事件邏輯等。
這僅僅是一項(xiàng)相對(duì)promise.than更為優(yōu)雅的語(yǔ)法來(lái)獲取promise的運(yùn)行結(jié)果,更容易閱讀和編寫(xiě)代碼而已。
不能將await用于任何標(biāo)準(zhǔn)函數(shù)
如果您嘗試將await運(yùn)行在任何未標(biāo)記為async的函數(shù)中,都會(huì)產(chǎn)生一個(gè)語(yǔ)法錯(cuò)誤
function f() { let promise = Promise.resolve(1); let result = await promise; // Syntax error }
我們?nèi)绻麤](méi)有使用async標(biāo)記函數(shù),那么我們就會(huì)得到這個(gè)語(yǔ)法錯(cuò)誤。換句話說(shuō),await僅可以運(yùn)行在async function中。
讓我們修改 Promises chaining 中的例子,使用async/await來(lái)重寫(xiě)這個(gè)例子。
我們需要將.then替換為await。
我們需要將函數(shù)修改為async function。
async function showAvatar() { // read our JSON let response = await fetch("/article/promise-chaining/user.json"); let user = await response.json(); // read github user let githubResponse = await fetch(`https://api.github.com/users/${user.name}`); let githubUser = await githubResponse.json(); // show the avatar let img = document.createElement("img"); img.src = githubUser.avatar_url; img.className = "promise-avatar-example"; document.body.append(img); // wait 3 seconds await new Promise((resolve, reject) => setTimeout(resolve, 3000)); img.remove(); return githubUser; } showAvatar();
相當(dāng)容易閱讀和理解對(duì)吧。
await 并不能在頂層環(huán)境中生效人們?cè)陂_(kāi)始使用await時(shí),總是容易忘記必須在async function內(nèi)部使用。比如以下代碼將會(huì)報(bào)錯(cuò):
// syntax error in top-level code let response = await fetch("/article/promise-chaining/user.json"); let user = await response.json();
所以我們需要聲明一個(gè)async function來(lái)包裹該段代碼。
await 可以接受 thenables類(lèi)似promise.then,await準(zhǔn)許使用then方法。需要申明的是,這里指的是一個(gè)非promise對(duì)象,但它持有.then方法,那么就可以配合await使用。
比如以下例子,await接受new Thenable(1):
class Thenable { constructor(num) { this.num = num; } then(resolve, reject) { alert(resolve); // function() { native code } // resolve with this.num*2 after 1000ms setTimeout(() => resolve(this.num * 2), 1000); // (*) } }; async function f() { // waits for 1 second, then result becomes 2 let result = await new Thenable(1); alert(result); } f();
如果await與一個(gè)含有.then方法的非promise對(duì)象組合,同時(shí)其支持resolve、reject兩個(gè)方法作為參數(shù)。那么await將會(huì)等待其中之一的函數(shù)被調(diào)用(注釋?zhuān)?)所在行)并在之后繼續(xù)運(yùn)行剩余代碼。
Async方法類(lèi)函數(shù)亦可以被定義為異步函數(shù),僅需將async置于函數(shù)聲明前。
類(lèi)似于:
class Waiter { async wait() { return await Promise.resolve(1); } } new Waiter() .wait() .then(alert); // 1
這和之前的其他代碼端是一樣的作用:應(yīng)用await返回一個(gè)promise對(duì)象。
錯(cuò)誤處理如果promise順利完成,那么await promise將返回一個(gè)值。但假如觸發(fā)了錯(cuò)誤,那么將在此行代碼中throw一個(gè)錯(cuò)誤。
以下代碼:
async function f() { await Promise.reject(new Error("Whoops!")); }
等同于:
async function f() { throw new Error("Whoops!"); }
在真實(shí)的運(yùn)行環(huán)境中,可能需要消耗一些時(shí)間來(lái)觸發(fā)錯(cuò)誤。所以await將會(huì)進(jìn)行等待,而之后拋出一個(gè)錯(cuò)誤。我們可以通過(guò)try…catch來(lái)捕獲錯(cuò)誤,同樣的方法也適用于throw:
async function f() { try { let response = await fetch("http://no-such-url"); } catch(err) { alert(err); // TypeError: failed to fetch } } f();
觸發(fā)了錯(cuò)誤之后,運(yùn)行代碼將跳轉(zhuǎn)至catch代碼塊。我們可以使用如下代碼:
async function f() { try { let response = await fetch("/no-user-here"); let user = await response.json(); } catch(err) { // catches errors both in fetch and response.json alert(err); } } f();
但如果我們沒(méi)有使用try…catch,那么將會(huì)在異步調(diào)用f()時(shí)觸發(fā)rejected。我們也可以添加.catch來(lái)處理錯(cuò)誤:
async function f() { let response = await fetch("http://no-such-url"); } // f() becomes a rejected promise f().catch(alert); // TypeError: failed to fetch // (*)
如果我們忘記添加.catch,我們將獲得一個(gè)未被捕獲的錯(cuò)誤。我們也可以使用一個(gè)全局事件捕獲方法來(lái)處理,參見(jiàn)Promise chaining。
async/await 和 promise.then/catch當(dāng)我們使用async/await時(shí),我們僅僅需要.then,因?yàn)?em>await會(huì)接受正確結(jié)果。我們可以使用try…catch來(lái)取代.catch。同時(shí)這也將更為便利。
但處于頂層代碼邏輯時(shí),我們的邏輯代碼處在async function以外,我們并不能直接使用await,所以添加.then/catch代碼塊來(lái)獲取最終結(jié)果是更為普遍的做法。
當(dāng)我們需要等待多個(gè)promises時(shí),我們可以使用Promise.all之后使用await:
// wait for the array of results let results = await Promise.all([ fetch(url1), fetch(url2), ... ]);
假如觸發(fā)了一個(gè)錯(cuò)誤,它也會(huì)和其他promise一樣工作:從運(yùn)行失敗的Promise.all節(jié)點(diǎn)中斷,之后我們可以通過(guò)try…catch來(lái)捕獲錯(cuò)誤。
總結(jié)async定以后的函數(shù)有兩層作用:
確保它總是返回一個(gè)promise。
允許在函數(shù)內(nèi)部使用await。
await關(guān)鍵詞確保js運(yùn)行時(shí)將會(huì)等待promise處理完畢,并且:
如果觸發(fā)了一個(gè)運(yùn)行錯(cuò)誤,promise運(yùn)行中斷,并在改處類(lèi)似觸發(fā)throw error。
此外,它將返回一個(gè)結(jié)果,所以我們可以將其賦值給一個(gè)變量。
我們一起提供了一個(gè)偉大的框架來(lái)更為簡(jiǎn)便的完成異步操作。
有了async/await的幫組,我們可以大幅減少使用promise.then/catch,但我們依然不應(yīng)該忘記這些技術(shù)是基于promises,很可能我們會(huì)不得不繼續(xù)使用promise的方法。同時(shí),Promise.all相當(dāng)適合等待多個(gè)任務(wù)順序執(zhí)行的操作。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/90046.html
摘要:控制臺(tái)將顯示回調(diào)地獄通常,回調(diào)只能由一個(gè)異步函數(shù)調(diào)用。更多資源使更友好規(guī)范使用異步函數(shù)簡(jiǎn)化異步編碼旅程異步編程是一項(xiàng)在中無(wú)法避免的挑戰(zhàn)。 JavaScript經(jīng)常聲稱(chēng)是_異步_。那是什么意思?它如何影響發(fā)展?近年來(lái)這種方法有何變化? 請(qǐng)思考以下代碼: result1 = doSomething1(); result2 = doSomething2(result1); 大多數(shù)語(yǔ)言都處理每...
摘要:控制臺(tái)將顯示回調(diào)地獄通常,回調(diào)只能由一個(gè)異步函數(shù)調(diào)用。更多資源使更友好規(guī)范使用異步函數(shù)簡(jiǎn)化異步編碼旅程異步編程是一項(xiàng)在中無(wú)法避免的挑戰(zhàn)。 JavaScript經(jīng)常聲稱(chēng)是_異步_。那是什么意思?它如何影響發(fā)展?近年來(lái)這種方法有何變化? 請(qǐng)思考以下代碼: result1 = doSomething1(); result2 = doSomething2(result1); 大多數(shù)語(yǔ)言都處理每...
摘要:控制臺(tái)將顯示回調(diào)地獄通常,回調(diào)只能由一個(gè)異步函數(shù)調(diào)用。更多資源使更友好規(guī)范使用異步函數(shù)簡(jiǎn)化異步編碼旅程異步編程是一項(xiàng)在中無(wú)法避免的挑戰(zhàn)。 JavaScript經(jīng)常聲稱(chēng)是_異步_。那是什么意思?它如何影響發(fā)展?近年來(lái)這種方法有何變化? 請(qǐng)思考以下代碼: result1 = doSomething1(); result2 = doSomething2(result1); 大多數(shù)語(yǔ)言都處理每...
摘要:的出現(xiàn),讓我們可以走出回調(diào)地獄,著實(shí)驚艷。我已經(jīng)開(kāi)始使用里的和關(guān)鍵字來(lái)簡(jiǎn)化的處理。異步任務(wù)在這個(gè)例子是執(zhí)行之后,一直在執(zhí)行完成才繼續(xù)下一個(gè)任務(wù)并沒(méi)有產(chǎn)生阻塞。最后這個(gè)函數(shù)處理了返回值并且返回了一個(gè)對(duì)象。依然很棒,但和使得它可維護(hù)性更好。 JavaScript Promises的出現(xiàn),讓我們可以走出回調(diào)地獄,著實(shí)驚艷。Promises 允許我們更好的引入和處理異步任務(wù),雖然如此,但引入好...
摘要:讓我們使用它從數(shù)組中返回一個(gè)值數(shù)組在中,我們可以這樣做,這是一種更簡(jiǎn)單的方法最重要的部分是創(chuàng)建數(shù)組,該數(shù)組立即調(diào)用所有的我們?cè)谥骱瘮?shù)中等待這些。所以在我們真正等待完成之前,主函數(shù)就退出了。 原文:https://pouchdb.com/2015/03/0... PouchDB最棘手的方面之一是它的API是異步的。在Stack Overflow、Github和IRC上,我看到了不少困惑的...
閱讀 896·2021-10-25 09:45
閱讀 3336·2021-09-22 14:58
閱讀 3904·2021-08-31 09:43
閱讀 950·2019-08-30 15:55
閱讀 950·2019-08-29 13:51
閱讀 1258·2019-08-29 13:02
閱讀 3514·2019-08-29 12:52
閱讀 1982·2019-08-26 13:27