JavaScript異步編程系列(三)——Async/await

async/await是一種方便使用promise的特殊語法。javascript

函數前面的async表示:此函數將會返回一個promise,若是函數返回的不是promise,將會包裝成一個已經resolved的promise。java

async function f() {
  return 1;
}
f().then(alert); // 1

// 至關於下面的寫法
async function f() {
  return Promise.resolve(1);
}
f().then(alert); // 1
複製代碼

await只在async函數中有效,普通函數中使用await會報語法錯誤。let value = await promise; 表示讓JavaScript引擎等待直到 promise 完成並返回結果。這個行爲不會耗費 CPU 資源,由於引擎能夠同時處理其餘任務:執行其餘腳本,處理事件等。promise

async function f() {
  let promise = new Promise((resolve, reject) => {
    setTimeout(() => resolve("done!"), 1000)
  });
  let result = await promise; // 等待直到 promise resolved後拿到result繼續往下執行
  alert(result); // "done!"
}
f();
複製代碼

await能夠接收Thenable對象(具備 then 方法的對象)並調用then方法,並將resolve,reject 做爲參數傳入。而後await等到這兩個方法中的某個被調用,再處理獲得的結果。markdown

class Thenable {
  constructor(num) {
    this.num = num;
  }
  then(resolve, reject) {
    setTimeout(() => resolve(this.num * 2), 1000);
  }
};
async function f() {
  // 等待 1 秒, result 變爲 2
  let result = await new Thenable(1);
  alert(result);
}
f();
複製代碼

若是想定義一個 async 的類方法,在方法前面添加 async 就能夠了:async

class Waiter {
  async wait() {
    return await Promise.resolve(1);
  }
}
new Waiter().wait().then(alert); // 1
複製代碼

錯誤處理

若是一個promise被resolved,await promise返回的就是其結果。 若是一個promise被rejected,就會拋出一個錯誤,就像在那一行有個 throw 語句那樣。函數

async function f() {
  await Promise.reject(new Error("Whoops!"));
}
// 至關於:
async function f() {
  throw new Error("Whoops!");
}
複製代碼

能夠用 try..catch 來捕獲上面的錯誤,就像對通常的 throw 語句那樣:oop

async function f() {
  try {
    let response = await fetch('http://no-such-url');
  } catch(err) {
    alert(err); // TypeError: failed to fetch
  }
}
f();
複製代碼

若是不使用 try..catch,由f() 產生的 promise 就會被reject,能夠在函數調用後添加 .catch 來處理錯誤。若是沒處理錯誤能夠使用全局的unhandledrejection事件來捕獲。fetch

async function f() {
  let response = await fetch('http://no-such-url');
}
// f() 變爲一個被reject的 promise
f().catch(alert); // TypeError: failed to fetch // (*)

複製代碼

當須要等待多個promise時,能夠用Promise.all搭配async/await使用:this

async () => {
  let results = await Promise.all([
    fetch(url1),
    fetch(url2),
    ...
  ]);
}
複製代碼

若是發生錯誤,也會正常傳遞:先從失敗的 promise 傳到 Promise.all,而後變成咱們能用 try..catch 處理的異常。url

執行順序

Async/await 是基於 promise 的,因此它內部使用相同的微任務隊列,而且相對宏任務來講具備更高的優先級。

async function f() {
  return 1;
}
(async () => {
    setTimeout(() => alert('timeout'), 0); // 3

    await f(); // 1

    alert('await'); // 2
})();
複製代碼

在一個普通的函數中,如何調用另外一個 async 函數而且拿到返回值?使用then,由於async函數返回一個settled promise。

async function wait() {
  await new Promise(resolve => setTimeout(resolve, 1000));
  return 10;
}
(function() {
  wait().then((value) => alert(value));
})();複製代碼
相關文章
相關標籤/搜索