20170702-異步編程之 async await

async await

  • async await是異步編程的另外一種解決方案es6

  • async函數是對Generator函數的改進編程

async的基本用法

async函數

async函數返回一個 Promise 實例,能夠使用then方法(爲返回的Promise實例)添加回調函數。當函數執行的時候,一旦遇到await就會先返回,等到異步操做完成,再接着執行函數體內後面的語句。服務器

  • 例 1:異步

clipboard.png

  • 上面代碼是一個獲取股票報價的函數,函數前面的async關鍵字,代表該函數內部有異步操做。調用該函數時,會當即返回一個Promise實例。async

  • async函數內部return語句返回的值,會成爲then方法回調函數的參數。異步編程

Promise對象的狀態變化

async函數返回的 Promise對象,必須等到內部全部await命令後面的 Promise 對象執行完,纔會發生狀態改變,除非遇到return語句或者拋出錯誤。也就是說,只有async函數內部的異步操做執行完,纔會執行then方法指定的回調函數。函數

await命令的基本用法

正常狀況下,await命令後面是一個Promise實例,若是不是,會被轉成一個當即resolvePromise實例。spa

async function f() {
  return await 123;
}

f().then(v => console.log(v))

等價於code

async function f() {
    return await new Promise(function(resolve){
        resolve(123)
    })
}
f().then(v => console.log(v))

等價於對象

async function f() {
    return await Promise.resolve('123')
}
f().then(v => console.log(v))
  • await語句的返回值是await命令後面Promise實例的結果(異步處理的結果)

function getResult() {
  return new Promise((resolve) => {
    resolve('result: 1000')  // resolve()方法的參數就是異步處理的結果
  });
}

async function asyncPrint() {
  const result = await getResult()  // 將異步處理的結果賦值給result
  return result
}

asyncPrint().then( (result) => { console.log(result) } ) //'result: 1000'

異常處理

若是await後面的異步操做出錯,那麼等同於async函數返回的 Promise 對象被reject

async function f() {
  await new Promise(function (resolve, reject) {
    throw new Error('出錯了');
  });
}

f()
.then(v => console.log(v))
.catch(e => console.log(e))
// Error:出錯了

防止出錯的方法,也是將其放在try...catch代碼塊之中。

async function f() {
  try {
    await new Promise(function (resolve, reject) {
      throw new Error('出錯了');
    });
  } catch(e) {
  }
  return await('hello world');
}

使用注意

  • 若是await後面的異步操做出錯,那麼等同於async函數返回的 Promise 對象被reject,因此最好把await命令放在try...catch代碼塊中。

async function myFunction() {
  try {
    await somethingThatReturnsAPromise();
  } catch (err) {
    console.log(err);
  }
}

// 另外一種寫法

async function myFunction() {
  await somethingThatReturnsAPromise()
  .catch(function (err) {
    console.log(err);
  });
}
  • 多個await命令後面的異步操做,若是不存在繼發關係,最好讓它們同時觸發。

let foo = await getFoo();
let bar = await getBar();

上面代碼中,getFoogetBar是兩個獨立的異步操做(即互不依賴),被寫成繼發關係(只有執行完getFoo操做,才能去執行getBar操做)。這樣比較耗時,由於只有getFoo完成之後,纔會執行getBar,徹底能夠讓它們同時觸發。

解釋:這裏的getFoogetBar方法會返回兩個Promise實例(假設是發起Ajax請求,請求foo和bar的內容),只有執行了方法,對應的操做纔會執行,若是寫成上面的形式,就會致使執行完getFoo的操做後(等待收到服務器的響應後),才能執行getBar的操做,這樣就成了同步,比較耗時,所以能夠將上面的寫法修改,使得在等待getFoo執行完的時間內(在等待服務器響應的期間)去執行執行getBar

記住:當函數執行的時候,一旦遇到await就會先返回,等到異步操做完成,再接着執行函數體內後面的語句。

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

// 寫法二
let fooPromise = getFoo();
let barPromise = getBar();
let foo = await fooPromise;
let bar = await barPromise;

上面兩種寫法,getFoogetBar都是同時觸發,這樣就會縮短程序的執行時間。

參考資料

ECMAScript 6 入門

相關文章
相關標籤/搜索