盤點JavaScript中Async/Await知識
大家好,我是進(jìn)階學(xué)習(xí)者。
一、前言
Async/await 是以更舒適的方式使用 promise 的一種特殊語法,同時它也非常易于理解和使用。
二、Async function
讓以 async 這個關(guān)鍵字開始。它可以被放置在一個函數(shù)前面。
如下所示:
- async function f() {
- return 1;
- }
在函數(shù)前面的 “async” 這個單詞表達(dá)了一個簡單的事情:即這個函數(shù)總是返回一個 promise。其他值將自動被包裝在一個 resolved 的 promise 中。
例如,下面這個函數(shù)返回一個結(jié)果為 1 的 resolved promise。
讓測試一下:
- async function f() {
- return 1;
- }
- f().then(alert); // 1
也可以顯式地返回一個 promise,結(jié)果是一樣的:
- async function f() {
- return Promise.resolve(1);
- }
- f().then(alert); // 1
注:
async 確保了函數(shù)返回一個 promise,也會將非 promise 的值包裝進(jìn)去。很簡單,對吧?但不僅僅這些。還有另外一個叫 await 的關(guān)鍵詞,它只在 async 函數(shù)內(nèi)工作,也非常酷。
三、Await
1. 語法
- // 只在 async 函數(shù)內(nèi)工作
- let value = await promise;
關(guān)鍵字 await 讓 JavaScript 引擎等待直到 promise 完成(settle)并返回結(jié)果。
這里的例就是一個 1 秒后 resolve 的 promise:
- async function f() {
- let promise = new Promise((resolve, reject) => {
- setTimeout(() => resolve("done!"), 1000)
- });
- let result = await promise; // 等待,直到 promise resolve (*)
- alert(result); // "done!"
- }
- f();
代碼解析:
這個函數(shù)在執(zhí)行的時候,“暫停”在了 (*) 那一行,并在 promise settle 時,拿到 result 作為結(jié)果繼續(xù)往下執(zhí)行。所以上面這段代碼在一秒后顯示 “done!”。
await 字面的意思就是讓 JavaScript 引擎等待直到 promise settle,然后以 promise 的結(jié)果繼續(xù)執(zhí)行。這個行為不會耗費任何 CPU 資源,因為引擎可以同時處理其他任務(wù):執(zhí)行其他腳本,處理事件等。
相比于 promise.then,它只是獲取 promise 的結(jié)果的一個更優(yōu)雅的語法,同時也更易于讀寫。
不能在普通函數(shù)中使用 await。
如果嘗試在非 async 函數(shù)中使用 await 的話,就會報語法錯誤:
- function f() {
- let promise = Promise.resolve(1);
- let result = await promise; // Syntax error
- }
如果函數(shù)前面沒有 async 關(guān)鍵字,就會得到一個語法錯誤。就像前面說的,await 只在 async 函數(shù) 中有效。
showAvatar() 例子,并將其改寫成 async/await 的形式:
需要用 await 替換掉 .then 的調(diào)用。
另外,需要在函數(shù)前面加上 async 關(guān)鍵字,以使它們能工作。
- async function showAvatar() {
- // 讀取的 JSON
- let response = await fetch('/article/promise-chaining/user.json');
- let user = await response.json();
- // 讀取 github 用戶信息
- let githubResponse = await fetch(`https://api.github.com/users/${user.name}`);
- let githubUser = await githubResponse.json();
- // 顯示頭像
- let img = document.createElement('img');
- img.src = githubUser.avatar_url;
- img.className = "promise-avatar-example";
- document.body.append(img);
- // 等待 3 秒
- await new Promise((resolve, reject) => setTimeout(resolve, 3000));
- img.remove();
- return githubUser;
- }
- showAvatar();
簡潔明了,是吧?比之前可強(qiáng)多了。await 不能在頂層代碼運(yùn)行。
這有一個用于演示的 Thenable 類
下面的 await 接受了該類的例子:
- class Thenable {
- constructor(num) {
- this.num = num;
- }
- then(resolve, reject) {
- alert(resolve);
- // 1000ms 后使用 this.num*2 進(jìn)行 resolve
- setTimeout(() => resolve(this.num * 2), 1000); // (*)
- }
- };
- async function f() {
- // 等待 1 秒,之后 result 變?yōu)?nbsp;2
- let result = await new Thenable(1);
- alert(result);
- }
- f();
運(yùn)行結(jié)果:
注:
如果 await 接收了一個非 promise 的但是提供了 .then 方法的對象,它就會調(diào)用這個 .then 方法,并將內(nèi)建的函數(shù) resolve 和 reject 作為參數(shù)傳入(就像它對待一個常規(guī)的 Promise executor 時一樣)。
然后 await 等待直到這兩個函數(shù)中的某個被調(diào)用(在上面這個例子中發(fā)生在 (*) 行),然后使用得到的結(jié)果繼續(xù)執(zhí)行后續(xù)任務(wù)。
2. Class 中的 async 方法
要聲明一個 class 中的 async 方法,只需在對應(yīng)方法前面加上 async 即可:
- class Waiter {
- async wait() {
- return await Promise.resolve(1);
- }
- }
- new Waiter()
- .wait()
- .then(alert); // 1
運(yùn)行結(jié)果:
注:
它確保了方法的返回值是一個 promise 并且可以在方法中使用 await。
四、總結(jié)
本文基于JavaScript基礎(chǔ),介紹了async的使用。函數(shù)前面的關(guān)鍵字 async 有兩個作用:讓這個函數(shù)總是返回一個 promise。允許在該函數(shù)內(nèi)使用 await。
這兩個關(guān)鍵字一起提供了一個很好的用來編寫異步代碼的框架,這種代碼易于閱讀也易于編寫。通過案例的分分析,圖文結(jié)合的方式,進(jìn)行詳細(xì)的講解,使用JavaScript語言,能夠讓讀者更好的理解。
代碼很簡單,希望能夠幫助你更好的學(xué)習(xí)。



































