async & await (譯)

JavaScript Promises的出現,讓咱們能夠走出回調地獄,着實驚豔。Promises 容許咱們更好的引入和處理異步任務,雖然如此,但引入好多的 then 仍是會讓代碼變的混亂。我已經開始使用 ES2017 裏的 asyncawait 關鍵字來簡化 promises 的處理。讓咱們一睹 asyncawait 的風采!web

快速入門

  • async 是函數聲明的關鍵字
  • await 用於 promises 處理過程當中
  • await 必須用在 async 聲明的函數內部,雖然 Chrome 已經支持「頂級的」的 await
  • async 函數返回 promises 對象,不關心函數的返回值是什麼
  • async/await 和 promises 的底層實現是同樣的
  • 大多數瀏覽器和 Nodejs 已經可用

asyncawait 的好處

  • 代碼更加清晰簡潔
  • 更少的回調,調試更加簡單
  • 容易從 promises 中的 then / catch 轉換
  • 代碼看起來自上而下,更少的縮進。

asyncawait 簡介

從實例入手要更簡單,咱們先來看一個簡單的 async/await 的使用方法:json

// 使用 async 定義函數,而後 await 才能使用
async function fetchContent() {
  // Instead of using fetch().then, use await
  let content = await fetch('/');
  let text = await content.text();
  
  // async 函數內,text 是響應值
  console.log(text);

  // Resolve this async function with the text
  return text;
}

// Use the async function
var promise = fetchContent().then(...);

首先使用 async 聲明函數;聲明以後,await 能夠用在該函數內部。await 關鍵字後面跟 promise:fetch API。異步任務(在這個例子是 fetch)執行以後,一直在執行完成才繼續下一個任務(並無產生阻塞)。最後這個函數處理了返回值而且返回了一個 promises 對象。promise

代碼自上而下,告別回調,異步處理變的更加簡單!瀏覽器

轉換 Promise 爲 await

當時間容許,你必定很想將你的 promise 的代碼升級到 await,讓咱們看下該怎麼作:babel

// Before: callback city!
fetch('/users.json')
  .then(response => response.json())
  .then(json => {
    console.log(json);
  })
  .catch(e => { console.log('error!'); })

// After: no more callbacks!
async function getJson() {
  try {
    let response = await fetch('/users.json');
    let json = await response.json();
    console.log(json);
  }
  catch(e) {
    console.log('Error!', e);
  }
}

從使用多個 thenawait 十分簡單,但你的代碼的維護性變得很高。異步

async / await 模式

聲明 async 函數有如下方式:async

匿名 Async 函數

let main = (async function() {
  let value = await fetch('/');
})();

Async 函數聲明

async function main() {
  let value = await fetch('/');
};

Async 函數賦值

let main = async function() {
  let value = await fetch('/');
};

// Arrow functions too!
let main = async () => {
  let value = await fetch('/');
};

Async 函數做爲參數

document.body.addEventListener('click', async function() {
  let value = await fetch('/');
});

對象和類方法

// Object property
let obj = {
  async method() {
    let value = await fetch('/');
  }
};

// Class methods
class MyClass {
  async myMethod() {
    let value = await fetch('/');
  }
}

正如你看到的,增長 async 函數十分簡單,並且能很好的適用各類函數建立的流程。函數

錯誤處理

傳統的 promises 容許使用 catch 回調處理 rejection,當你使用 await,最好使用 try/catchpost

try {
  let x = await myAsyncFunction();
}
catch(e) {
 // Error!
}

老式的 try/catch 不如 promises 的 catch 優雅,但在這裏,它很給力!fetch

並行

Google 的Jake Archibald在Async functions document中提出了一個完美的觀點:不要用 await 使得任務變的太序列化。也就是說對於能夠同時執行的任務,先觸發任務而後再使用 await,而不是直接使用 await 使得任務像堆棧式同樣的存儲。

// Will take 1000ms total!
async function series() {
  await wait(500);
  await wait(500);
  return "done!";
}

// Would take only 500ms total!
async function parallel() {
  const wait1 = wait(500);
  const wait2 = wait(500);
  await wait1;
  await wait2;
  return "done!";
}

第一個代碼塊反面例子,第二個 await 須要等待第一個 await 執行完畢後才執行,第二個代碼塊是一個更好的方法,同時觸發了兩個任務,而後才使用 await;這樣作可使得多個異步操做同時執行!

Promise.all 等價方式

Primises API 中我最愛的 API 之一就是 Promise.all:當多有任務完成後纔會觸發回調。async / await 中沒有等價的操做,可是這篇文章提供了一個很好的解決方案:

let [foo, bar] = await Promise.all([getFoo(), getBar()]);

請記住,async / await和 promises 在底層實現上是一致的,因此咱們能夠簡單的等待(await)全部的 promises 任務結束!

如今大多數瀏覽器均可以使用 asyncawait,Nodejs 同樣可用,老版本的Nodejs可使用 transform-async-to-generator 這個 babel 插件來使用 asyncawait。Promises 依然很棒,但 asyncawait 使得它可維護性更好。

原文地址:https://davidwalsh.name/async...

博客原地址:http://zhaojizong.online/post...

相關文章
相關標籤/搜索