成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

[譯]帶你理解 Async/await

xiaochao / 2950人閱讀

摘要:所以是在一秒后顯示的。這個(gè)行為不會(huì)耗費(fèi)資源,因?yàn)橐婵梢酝瑫r(shí)處理其他任務(wù)執(zhí)行其他腳本,處理事件等。每個(gè)回調(diào)首先被放入微任務(wù)隊(duì)列然后在當(dāng)前代碼執(zhí)行完成后被執(zhí)行。,函數(shù)是異步的,但是會(huì)立即運(yùn)行。否則,就返回結(jié)果,并賦值。

「async/await」是 promises 的另一種更便捷更流行的寫法,同時(shí)它也更易于理解和使用。

Async functions

讓我們以 async 這個(gè)關(guān)鍵字開始。它可以被放置在任何函數(shù)前面,像下面這樣:

async function f() {
  return 1;
}

在函數(shù)前面的「async」這個(gè)單詞表達(dá)了一個(gè)簡(jiǎn)單的事情:即這個(gè)函數(shù)總是返回一個(gè) promise。即使這個(gè)函數(shù)在語(yǔ)法上返回了一個(gè)非 promise 的值,加了「async」這個(gè)關(guān)鍵字就會(huì)指示 JavaScript 引擎自動(dòng)將返回值包裝成一個(gè)解析后的 promise。

例如,以下的代碼就返回了一個(gè)以 1 為結(jié)果的解析后的 promise, 讓我們?cè)囈幌拢?/p>

async function f() {
  return 1;
}

f().then(alert); // 1

... 我們也可以顯式返回一個(gè) promise,結(jié)果是一樣的:

async function f() {
  return Promise.resolve(1);
}

f().then(alert); // 1

所以說(shuō),async 確保了函數(shù)的返回值是一個(gè) promise,也會(huì)包裝非 promise 的值。很簡(jiǎn)單是吧?但是還沒(méi)完。還有一個(gè)關(guān)鍵字叫 await,它只在 async 函數(shù)中有效,也非???。

Await

語(yǔ)法如下:

// 只在 async 函數(shù)中有效
let value = await promise;

關(guān)鍵字 await 讓 JavaScript 引擎等待直到 promise 完成并返回結(jié)果。

這里的例子就是一個(gè) 1 秒后解析的 promise:

async function f() {

  let promise = new Promise((resolve, reject) => {
    setTimeout(() => resolve("done!"), 1000)
  });

  let result = await promise; // 等待直到 promise 解析 (*)

  alert(result); // "done!"
}

f();

這個(gè)函數(shù)在執(zhí)行的時(shí)候,「暫停」在了 (*) 那一行,并且當(dāng) promise 完成后,拿到 result 作為結(jié)果繼續(xù)往下執(zhí)行。所以「done!」是在一秒后顯示的。

劃重點(diǎn):await 字面的意思就是讓 JavaScript 引擎等待直到 promise 狀態(tài)完成,然后以完成的結(jié)果繼續(xù)執(zhí)行。這個(gè)行為不會(huì)耗費(fèi) CPU 資源,因?yàn)橐婵梢酝瑫r(shí)處理其他任務(wù):執(zhí)行其他腳本,處理事件等。

相比 promise.then 來(lái)獲取 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; // 語(yǔ)法錯(cuò)誤
}

如果函數(shù)前面沒(méi)有 async 關(guān)鍵字,我們就會(huì)得到一個(gè)語(yǔ)法錯(cuò)誤。就像前面說(shuō)的,await 只在 async 函數(shù) 中有效。

讓我們拿 Promises 鏈那一章的 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)行
剛開始使用 await 的人常常會(huì)忘記 await 不能用在頂層代碼中。如,下面這樣就不行:

// 用在頂層代碼中會(huì)報(bào)語(yǔ)法錯(cuò)誤
let response = await fetch("/article/promise-chaining/user.json");
let user = await response.json();

我們可以將其包裹在一個(gè)匿名 async 函數(shù)中,如:

(async () => {
  let response = await fetch("/article/promise-chaining/user.json");
  let user = await response.json();
  ...
})();

await 可以接收「thenables」
promise.then 那樣,await 被允許接收 thenable 對(duì)象(具有 then 方法的對(duì)象)。有些對(duì)象雖然不是 promise,但是卻兼容 promise,如果這些對(duì)象支持 .then,那么就可以對(duì)它們使用 await。

下面是一個(gè) Thenable 類,await 接收了該類的實(shí)例:

class Thenable {
  constructor(num) {
    this.num = num;
  }
  then(resolve, reject) {
    alert(resolve);
    // 1 秒后解析為 this.num*2
    setTimeout(() => resolve(this.num * 2), 1000); // (*)
  }
};

async function f() {
  // 等待 1 秒, result 變?yōu)?2
  let result = await new Thenable(1);
  alert(result);
}

f();

如果 await 接收了一個(gè)非 promise 的但是提供了 .then 方法的對(duì)象,它就會(huì)調(diào)用這個(gè) then 方法,并將原生函數(shù) resolve,reject 作為參數(shù)傳入。然后 await 等到這兩個(gè)方法中的某個(gè)被調(diào)用(在例子中發(fā)生在(*)的那一行),再處理得到的結(jié)果。

Async methods
如果想定義一個(gè) async 的類方法,在方法前面添加 async 就可以了:

class Waiter {
  async wait() {
    return await Promise.resolve(1);
  }
}

new Waiter()
  .wait()
  .then(alert); // 1
異常處理

如果一個(gè) promise 正常解析,await promise 返回的就是其結(jié)果。但是如果 promise 被拒絕,就會(huì)拋出一個(gè)錯(cuò)誤,就像在那一行有個(gè) throw 語(yǔ)句那樣。

這里的代碼:

async function f() {
  await Promise.reject(new Error("Whoops!"));
}

...和下面是一樣的:

async function f() {
  throw new Error("Whoops!");
}

在真實(shí)的環(huán)境下,promise 被拒絕前通常會(huì)等待一段時(shí)間。所以 await 會(huì)等待,然后拋出一個(gè)錯(cuò)誤。

我們可以用 try...catch 來(lái)捕獲上面的錯(cuò)誤,就像對(duì)一般的 throw 語(yǔ)句那樣:

async function f() {

  try {
    let response = await fetch("http://no-such-url");
  } catch(err) {
    alert(err); // TypeError: failed to fetch
  }
}

f();

如果有錯(cuò)誤發(fā)生,代碼就會(huì)跳到 catch 塊中。當(dāng)然也可以用 try 包裹多行 await 代碼:

async function f() {

  try {
    let response = await fetch("/no-user-here");
    let user = await response.json();
  } catch(err) {
    // 捕獲到 fetch 和 response.json 中的錯(cuò)誤
    alert(err);
  }
}

f();

如果我們不使用 try...catch,由f() 產(chǎn)生的 promise 就會(huì)被拒絕。我們可以在函數(shù)調(diào)用后添加 .catch 來(lái)處理錯(cuò)誤:

async function f() {
  let response = await fetch("http://no-such-url");
}

// f() 變?yōu)橐粋€(gè)被拒絕的 promise
f().catch(alert); // TypeError: failed to fetch // (*)

如果我們忘了添加 .catch,我們就會(huì)得到一個(gè)未處理的 promise 錯(cuò)誤(顯示在控制臺(tái))。我們可以通過(guò)在錯(cuò)誤處理與 Promise 章節(jié)講的全局事件處理器來(lái)捕獲這些。

async/awaitpromise.then/catch
當(dāng)我們使用 async/await 時(shí),幾乎就不會(huì)用到 .then 了,因?yàn)闉槲覀?b>await 處理了異步等待。并且我們可以用 try...catch 來(lái)替代 .catch。這通常更加方便(當(dāng)然不是絕對(duì)的)。

但是當(dāng)我們?cè)陧攲哟a,外面并沒(méi)有任何 async 函數(shù),我們?cè)谡Z(yǔ)法上就不能使用 await 了,所以這時(shí)候就可以用 .then/catch 來(lái)處理結(jié)果和異常。

就像上面代碼的 (*) 那行一樣。

async/await 可以和 Promise.all 一起使用
當(dāng)我們需要同時(shí)等待多個(gè) promise 時(shí),我們可以用 Promise.all 來(lái)包裹他們,然后使用 await

// 等待多個(gè) promise 結(jié)果
let results = await Promise.all([
  fetch(url1),
  fetch(url2),
  ...
 ]);

如果發(fā)生錯(cuò)誤,也會(huì)正常傳遞:先從失敗的 promise 傳到 Promise.all,然后變成我們能用 try...catch 處理的異常。

Microtask queue

我們?cè)谖⑷蝿?wù)和事件循環(huán)章節(jié)講過(guò),promise 回調(diào)是異步執(zhí)行的。每個(gè) .then/catch/finally 回調(diào)首先被放入「微任務(wù)隊(duì)列」然后在當(dāng)前代碼執(zhí)行完成后被執(zhí)行。

Async/await 是基于 promise 的,所以它內(nèi)部使用相同的微任務(wù)隊(duì)列,并且相對(duì)宏任務(wù)來(lái)說(shuō)具有更高的優(yōu)先級(jí)。

例如,看代碼:

setTimeout(handler, 0),應(yīng)該以零延遲運(yùn)行 handler 函數(shù)。

let x = await f(),函數(shù) f() 是異步的,但是會(huì)立即運(yùn)行。

那么如果 awaitsetTimeout 下面,哪一個(gè)先執(zhí)行呢?

async function f() {
  return 1;
}

(async () => {
    setTimeout(() => alert("timeout"), 0);

    await f();

    alert("await");
})();

這里很確定:await 總是先完成,因?yàn)椋ㄗ鳛槲⑷蝿?wù))它相比 setTimeout 具有更高的優(yōu)先級(jí)。

總結(jié)

函數(shù)前面的關(guān)鍵字 async 有兩個(gè)作用:

讓這個(gè)函數(shù)返回一個(gè) promise

允許在函數(shù)內(nèi)部使用 await

這個(gè) await 關(guān)鍵字又讓 JavaScript 引擎等待直到 promise 完成,然后:

如果有錯(cuò)誤,就會(huì)拋出異常,就像那里有一個(gè) throw error 語(yǔ)句一樣。

否則,就返回結(jié)果,并賦值。

這兩個(gè)關(guān)鍵字一起用就提供了一個(gè)很棒的方式來(lái)控制異步代碼,并且易于讀寫。

有了 async/await 我們就幾乎不需要使用 promise.then/catch,但是不要忘了它們是基于 promise 的,所以在有些時(shí)候(如在最外層代碼)我們就可以用 promise 的形式。再有就是 Promise.all 可以幫助我們同時(shí)處理多個(gè)異步任務(wù)。

原文鏈接

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/104748.html

相關(guān)文章

  • 前端基礎(chǔ)

    摘要:談起閉包,它可是兩個(gè)核心技術(shù)之一異步基于打造前端持續(xù)集成開發(fā)環(huán)境本文將以一個(gè)標(biāo)準(zhǔn)的項(xiàng)目為例,完全拋棄傳統(tǒng)的前端項(xiàng)目開發(fā)部署方式,基于容器技術(shù)打造一個(gè)精簡(jiǎn)的前端持續(xù)集成的開發(fā)環(huán)境。 這一次,徹底弄懂 JavaScript 執(zhí)行機(jī)制 本文的目的就是要保證你徹底弄懂javascript的執(zhí)行機(jī)制,如果讀完本文還不懂,可以揍我。 不論你是javascript新手還是老鳥,不論是面試求職,還是日...

    graf 評(píng)論0 收藏0
  • async/await 應(yīng)知應(yīng)會(huì)

    摘要:原文地址原文作者翻譯作者是在版本中引入的,它對(duì)于中的異步編程而言是一個(gè)巨大的提升??赡軙?huì)產(chǎn)生誤導(dǎo)一些文章把和進(jìn)行了比較,同時(shí)說(shuō)它是異步編程演變過(guò)程中的下一代解決方案,對(duì)此我不敢茍同。結(jié)論在中引入的關(guān)鍵字無(wú)疑是對(duì)異步編程的一大加強(qiáng)。 原文地址: https://hackernoon.com/javasc...原文作者: Charlee Li 翻譯作者: Xixi20160512 asy...

    Ku_Andrew 評(píng)論0 收藏0
  • 2017-07-19 前端日?qǐng)?bào)

    摘要:前端日?qǐng)?bào)精選開發(fā)常見(jiàn)問(wèn)題集錦前端碼農(nóng)的自我修養(yǎng)虛擬內(nèi)部是如何工作的譯知乎專欄并不慢,只是你使用姿勢(shì)不對(duì)一份優(yōu)化指南掘金老司機(jī)帶你秒懂內(nèi)存管理第一部中文免費(fèi)公開課前端面試的大關(guān)鍵點(diǎn),你到了嗎知乎專欄高效開發(fā)與設(shè)計(jì)姐的圖片二三 2017-07-19 前端日?qǐng)?bào) 精選 VueJS 開發(fā)常見(jiàn)問(wèn)題集錦 - 前端碼農(nóng)的自我修養(yǎng) - SegmentFault虛擬 DOM 內(nèi)部是如何工作的?[譯]Hig...

    iflove 評(píng)論0 收藏0
  • 令人費(fèi)解的 async/await 執(zhí)行順序

    摘要:?jiǎn)栴}的關(guān)鍵在于其執(zhí)行過(guò)程中的微任務(wù)數(shù)量,下文中我們需要用上述代碼中的方式對(duì)微任務(wù)的執(zhí)行順序進(jìn)行標(biāo)記,以輔助我們理解這其中的執(zhí)行過(guò)程。 原文發(fā)布在掘金社區(qū):https://juejin.im/post/5c3cc981f265da616a47e028 起源 2019年了,相信大家對(duì) Promise 和 async/await 都不再陌生了。 前幾日,我在社區(qū)讀到了一篇關(guān)于 async/...

    WilsonLiu95 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<