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





















 
 
 











 
 
 
 