摘要:是一種與協作的特殊的語法。換句話說,僅可以運行在中。所以將會進行等待,而之后拋出一個錯誤。同時這也將更為便利。允許在函數內部使用。關鍵詞確保運行時將會等待處理完畢,并且如果觸發了一個運行錯誤,運行中斷,并在改處類似觸發。
Async函數“async/await”是一種與“promise”協作的特殊的語法。它使得異步工作更加容易理解和使用。
我們從async關鍵詞開始,它可以被放置在任何函數的開頭位置,比如:
async function f() { return 1; }
這里的async表示:該函數將始終返回一個promise。即使您的代碼沒有顯式返回一個promise,在JavaScript運行時也會自動包裝一個promise,用于返回指定的值。
在這個例子中,這段代碼將會返回一個result為1的promise:
async function f() { return 1; } f().then(alert); // 1
當然,我們也可以顯式的返回一個promise:
async function f() { return Promise.resolve(1); } f().then(alert); // 1
async確保了函數會返回一個promise。挺簡單的對吧?接下來,是另一個關鍵詞await,僅僅能在async標記的函數中生效。
Await語法說明:
//該段代碼僅僅能在 async 標記的函數中生效 let value = await promise;
關鍵詞await確保JavaScript運行時將會等待promise執行完畢并返回結果。
下面是一段使用promise并在一秒后返回結果的例子:
async function f() { let promise = new Promise((resolve, reject) => { setTimeout(() => resolve("done!"), 1000) }); let result = await promise; // 等待至promise獲得結果 (*) alert(result); // "done!" } f();
該函數在運行至await時,執行了“pauses”操作,直至promise執行完畢后重新執行接下來的代碼。所以該段代碼將在一秒后顯示“done!”。
讓我們強調一遍:await將順序使得JavaScript的運行時等待promise執行完畢,而后繼續運行余下代碼。等待時的操作并不會消耗任何CPU資源,因為此時的運行時可以同時執行其他操作:執行其他的代碼,處理事件邏輯等。
這僅僅是一項相對promise.than更為優雅的語法來獲取promise的運行結果,更容易閱讀和編寫代碼而已。
不能將await用于任何標準函數
如果您嘗試將await運行在任何未標記為async的函數中,都會產生一個語法錯誤
function f() { let promise = Promise.resolve(1); let result = await promise; // Syntax error }
我們如果沒有使用async標記函數,那么我們就會得到這個語法錯誤。換句話說,await僅可以運行在async function中。
讓我們修改 Promises chaining 中的例子,使用async/await來重寫這個例子。
我們需要將.then替換為await。
我們需要將函數修改為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();
相當容易閱讀和理解對吧。
await 并不能在頂層環境中生效人們在開始使用await時,總是容易忘記必須在async function內部使用。比如以下代碼將會報錯:
// syntax error in top-level code let response = await fetch("/article/promise-chaining/user.json"); let user = await response.json();
所以我們需要聲明一個async function來包裹該段代碼。
await 可以接受 thenables類似promise.then,await準許使用then方法。需要申明的是,這里指的是一個非promise對象,但它持有.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與一個含有.then方法的非promise對象組合,同時其支持resolve、reject兩個方法作為參數。那么await將會等待其中之一的函數被調用(注釋(*)所在行)并在之后繼續運行剩余代碼。
Async方法類函數亦可以被定義為異步函數,僅需將async置于函數聲明前。
類似于:
class Waiter { async wait() { return await Promise.resolve(1); } } new Waiter() .wait() .then(alert); // 1
這和之前的其他代碼端是一樣的作用:應用await返回一個promise對象。
錯誤處理如果promise順利完成,那么await promise將返回一個值。但假如觸發了錯誤,那么將在此行代碼中throw一個錯誤。
以下代碼:
async function f() { await Promise.reject(new Error("Whoops!")); }
等同于:
async function f() { throw new Error("Whoops!"); }
在真實的運行環境中,可能需要消耗一些時間來觸發錯誤。所以await將會進行等待,而之后拋出一個錯誤。我們可以通過try…catch來捕獲錯誤,同樣的方法也適用于throw:
async function f() { try { let response = await fetch("http://no-such-url"); } catch(err) { alert(err); // TypeError: failed to fetch } } f();
觸發了錯誤之后,運行代碼將跳轉至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();
但如果我們沒有使用try…catch,那么將會在異步調用f()時觸發rejected。我們也可以添加.catch來處理錯誤:
async function f() { let response = await fetch("http://no-such-url"); } // f() becomes a rejected promise f().catch(alert); // TypeError: failed to fetch // (*)
如果我們忘記添加.catch,我們將獲得一個未被捕獲的錯誤。我們也可以使用一個全局事件捕獲方法來處理,參見Promise chaining。
async/await 和 promise.then/catch當我們使用async/await時,我們僅僅需要.then,因為await會接受正確結果。我們可以使用try…catch來取代.catch。同時這也將更為便利。
但處于頂層代碼邏輯時,我們的邏輯代碼處在async function以外,我們并不能直接使用await,所以添加.then/catch代碼塊來獲取最終結果是更為普遍的做法。
當我們需要等待多個promises時,我們可以使用Promise.all之后使用await:
// wait for the array of results let results = await Promise.all([ fetch(url1), fetch(url2), ... ]);
假如觸發了一個錯誤,它也會和其他promise一樣工作:從運行失敗的Promise.all節點中斷,之后我們可以通過try…catch來捕獲錯誤。
總結async定以后的函數有兩層作用:
確保它總是返回一個promise。
允許在函數內部使用await。
await關鍵詞確保js運行時將會等待promise處理完畢,并且:
如果觸發了一個運行錯誤,promise運行中斷,并在改處類似觸發throw error。
此外,它將返回一個結果,所以我們可以將其賦值給一個變量。
我們一起提供了一個偉大的框架來更為簡便的完成異步操作。
有了async/await的幫組,我們可以大幅減少使用promise.then/catch,但我們依然不應該忘記這些技術是基于promises,很可能我們會不得不繼續使用promise的方法。同時,Promise.all相當適合等待多個任務順序執行的操作。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/90046.html
摘要:控制臺將顯示回調地獄通常,回調只能由一個異步函數調用。更多資源使更友好規范使用異步函數簡化異步編碼旅程異步編程是一項在中無法避免的挑戰。 JavaScript經常聲稱是_異步_。那是什么意思?它如何影響發展?近年來這種方法有何變化? 請思考以下代碼: result1 = doSomething1(); result2 = doSomething2(result1); 大多數語言都處理每...
摘要:控制臺將顯示回調地獄通常,回調只能由一個異步函數調用。更多資源使更友好規范使用異步函數簡化異步編碼旅程異步編程是一項在中無法避免的挑戰。 JavaScript經常聲稱是_異步_。那是什么意思?它如何影響發展?近年來這種方法有何變化? 請思考以下代碼: result1 = doSomething1(); result2 = doSomething2(result1); 大多數語言都處理每...
摘要:控制臺將顯示回調地獄通常,回調只能由一個異步函數調用。更多資源使更友好規范使用異步函數簡化異步編碼旅程異步編程是一項在中無法避免的挑戰。 JavaScript經常聲稱是_異步_。那是什么意思?它如何影響發展?近年來這種方法有何變化? 請思考以下代碼: result1 = doSomething1(); result2 = doSomething2(result1); 大多數語言都處理每...
摘要:的出現,讓我們可以走出回調地獄,著實驚艷。我已經開始使用里的和關鍵字來簡化的處理。異步任務在這個例子是執行之后,一直在執行完成才繼續下一個任務并沒有產生阻塞。最后這個函數處理了返回值并且返回了一個對象。依然很棒,但和使得它可維護性更好。 JavaScript Promises的出現,讓我們可以走出回調地獄,著實驚艷。Promises 允許我們更好的引入和處理異步任務,雖然如此,但引入好...
摘要:讓我們使用它從數組中返回一個值數組在中,我們可以這樣做,這是一種更簡單的方法最重要的部分是創建數組,該數組立即調用所有的我們在主函數中等待這些。所以在我們真正等待完成之前,主函數就退出了。 原文:https://pouchdb.com/2015/03/0... PouchDB最棘手的方面之一是它的API是異步的。在Stack Overflow、Github和IRC上,我看到了不少困惑的...
閱讀 867·2021-10-25 09:45
閱讀 3284·2021-09-22 14:58
閱讀 3844·2021-08-31 09:43
閱讀 914·2019-08-30 15:55
閱讀 917·2019-08-29 13:51
閱讀 1225·2019-08-29 13:02
閱讀 3483·2019-08-29 12:52
閱讀 1961·2019-08-26 13:27