ES7之async/await 同步還是非同步

辰辰沉沉大辰沉發表於2018-02-24

async/await作為ES7的標準被視作javascript非同步函式操作的終極解決方案(超越Promise和Generator)越來越受到重視,而隨著前端構建工具的蓬勃發展,通過配置babel我們在專案中也可以直接使用這一新特性而無需太過在意瀏覽器的相容性問題。

有很多技術部落格對這兩個概念有非常棒的闡述,我之所以自己再寫一篇主要是為了筆下走一遍加深理解同時方便以後翻看。也是因為最近在做的一件事情,是將我們Angular4 + Typescript專案中的Promise操作全部替換為async/await。藉著這個機會把這兩個關鍵字用一個最簡單的例子再總結一下

MDN async

MDN await

定義

呼叫async函式時會返回一個Promise物件。當這個async函式返回一個值時,Promise的resolve方法會負責傳遞這個值;當async函式丟擲異常時,Promise 的 reject 方法也會傳遞這個異常值。

async函式中可能會有await表示式,這會使async函式暫停執行,等待表示式中的 Promise 解析完成後繼續執行async函式並返回解決結果。

async/await的目的是在promises的基礎上進一步簡化非同步的同步呼叫,它能對一組Promises執行一些操作。正如Promises類似於結構化回撥,async/await類似於組合生成器和promises。

總結

上面是官網的相關描述,從這裡可以提煉出以下幾個關鍵點:

- async/await 本質上依然是基於Promise,但在使用上更加簡便符合自然習慣。
- async函式內部同步執行。await之間相當於.then。
- async函式外部的呼叫非同步執行
- 需要try/catch await應對promise reject的情況。

栗子

下面是一個簡單的例子涵蓋上面總結的四點:

function resolveAfter2Seconds(x) {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(x);
    }, 2000);
  });
}

function resolveInPromiseRightNow(x) {
  return new Promise(resolve => {
      resolve('data from previous await: ' +  x);
  });
}

return new Promise((resolve, reject) => {
      reject('reject' );
  });
}

function fn1() {
  console.log('normal function');
}

// await只能在async函式中執行並且在async中是阻塞的
async function asyncFunction() {
  var x = await resolveAfter2Seconds('resolve after 2s');
  console.log(x); 
  console.log('message between 2 await');
  var y = await resolveInPromiseRightNow(x);
  console.log(y);

  try {
    await rejectInPromise();
  } catch(ex) {
    console.log(ex);
  }
}

// .then說明Promise本質
asyncFunction().then(() => {
  console.log('await completed');
});

fn1(); 

/// 結果
// normal function

/// 2s後

// resolve after 2s
// message between 2 await
// data from previous await: resolve after 2s
// reject
// await completed

相關文章