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