淺談async/await

ES7的async/await語法在2016年就已經提出來了,慚愧的是我最近才接觸使用,,下面來聊聊express

解決了什麼問題

在async/await以前,咱們有三種方式寫異步代碼npm

  1. 嵌套回調promise

  2. 以Promise爲主的鏈式回調瀏覽器

  3. 使用Generatorsbabel

可是,這三種寫起來都不夠優雅,ES7作了優化改進,async/await應運而生,async/await相比較Promise 對象then 函數的嵌套,與 Generator 執行的繁瑣(須要藉助co才能自動執行,不然得手動調用next() ), Async/Await 可讓你輕鬆寫出同步風格的代碼同時又擁有異步機制,更加簡潔,邏輯更加清晰。異步

async/await特色

  1. async/await更加語義化,async 是「異步」的簡寫,async function 用於申明一個 function 是異步的; await,能夠認爲是async wait的簡寫, 用於等待一個異步方法執行完成;async

  2. async/await是一個用同步思惟解決異步問題的方案(等結果出來以後,代碼纔會繼續往下執行)函數

  3. 能夠經過多層 async function 的同步寫法代替傳統的callback嵌套優化

async function語法

  • 自動將常規函數轉換成Promise,返回值也是一個Promise對象3d

  • 只有async函數內部的異步操做執行完,纔會執行then方法指定的回調函數

  • 異步函數內部可使用await

async function name([param[, param[, ... param]]]) { statements }
name: 函數名稱。
param:  要傳遞給函數的參數的名稱
statements: 函數體語句。
返回值: 返回的Promise對象會以async function的返回值進行解析,或者以該函數拋出的異常進行回絕。

image.png

await語法

  • await 放置在Promise調用以前,await 強制後面點代碼等待,直到Promise對象resolve,獲得resolve的值做爲await表達式的運算結果

  • await只能在async函數內部使用,用在普通函數裏就會報錯
[return_value] = await expression;

expression:  一個 Promise  對象或者任何要等待的值。

返回值:返回 Promise 對象的處理結果。若是等待的不是 Promise 對象,則返回該值自己。

image.png

錯誤處理

在async函數裏,不管是Promise reject的數據仍是邏輯報錯,都會被默默吞掉,因此最好把await放入try{}catch{}中,catch可以捕捉到Promise對象rejected的數據或者拋出的異常

function timeout(ms) {

  return new Promise((resolve, reject) => {

    setTimeout(() => {reject('error')}, ms);  //reject模擬出錯,返回error

  });

}

async function asyncPrint(ms) {

  try {

     console.log('start');

     await timeout(ms);  //這裏返回了錯誤

     console.log('end');  //因此這句代碼不會被執行了

  } catch(err) {

     console.log(err); //這裏捕捉到錯誤error

  }

}

asyncPrint(1000);

若是不用try/catch的話,也能夠像下面這樣處理錯誤(由於async函數執行後返回一個promise)

function timeout(ms) {

  return new Promise((resolve, reject) => {

    setTimeout(() => {reject('error')}, ms);  //reject模擬出錯,返回error

  });

}

async function asyncPrint(ms) {

  console.log('start');

  await timeout(ms)

  console.log('end');  //這句代碼不會被執行了

}

asyncPrint(1000).catch(err => {

    console.log(err); // 從這裏捕捉到錯誤

});

若是你不想讓錯誤中斷後面代碼的執行,能夠提早截留住錯誤,像下面

function timeout(ms) {

  return new Promise((resolve, reject) => {

    setTimeout(() => {

        reject('error')

    }, ms);  //reject模擬出錯,返回error

  });

}

async function asyncPrint(ms) {

  console.log('start');

  await timeout(ms).catch(err => {  // 注意要用catch

console.log(err) 

  })

  console.log('end');  //這句代碼會被執行

}

asyncPrint(1000);

使用場景

多個await命令的異步操做,若是不存在依賴關係(後面的await不依賴前一個await返回的結果),用Promise.all()讓它們同時觸發

function test1 () {
    return new Promise((resolve, reject) => {

        setTimeout(() => {

            resolve(1)

        }, 1000)

    })

}

function test2 () {

    return new Promise((resolve, reject) => {

        setTimeout(() => {

            resolve(2)

        }, 2000)

    })

}

async function exc1 () {

    console.log('exc1 start:',Date.now())

    let res1 = await test1();

    let res2 = await test2(); // 不依賴 res1 的值

    console.log('exc1 end:', Date.now())

}

async function exc2 () {

    console.log('exc2 start:',Date.now())

    let [res1, res2] = await Promise.all([test1(), test2()])

    console.log('exc2 end:', Date.now())

}

exc1();

exc2();

exc1 的兩個並列await的寫法,比較耗時,只有test1執行完了纔會執行test2

你能夠在瀏覽器的Console裏嘗試一下,會發現exc2的用Promise.all執行更快一些

image.png

兼容性

image.png

在本身的項目中使用

經過 babel 來使用。

只須要設置 presets 爲 stage-3 便可。

 安裝依賴:

npm install babel-preset-es2015 babel-preset-stage-3 babel-runtime babel-plugin-transform-runtime

修改.babelrc:

 "presets": ["es2015", "stage-3"],

 "plugins": ["transform-runtime"]

    
這樣就能夠在項目中使用 async 函數了。

image.png

---恢復內容結束---

ES7的async/await語法在2016年就已經提出來了,慚愧的是我最近才接觸使用,,下面來聊聊

解決了什麼問題

在async/await以前,咱們有三種方式寫異步代碼

  1. 嵌套回調

  2. 以Promise爲主的鏈式回調

  3. 使用Generators

可是,這三種寫起來都不夠優雅,ES7作了優化改進,async/await應運而生,async/await相比較Promise 對象then 函數的嵌套,與 Generator 執行的繁瑣(須要藉助co才能自動執行,不然得手動調用next() ), Async/Await 可讓你輕鬆寫出同步風格的代碼同時又擁有異步機制,更加簡潔,邏輯更加清晰。

async/await特色

  1. async/await更加語義化,async 是「異步」的簡寫,async function 用於申明一個 function 是異步的; await,能夠認爲是async wait的簡寫, 用於等待一個異步方法執行完成;

  2. async/await是一個用同步思惟解決異步問題的方案(等結果出來以後,代碼纔會繼續往下執行)

  3. 能夠經過多層 async function 的同步寫法代替傳統的callback嵌套

async function語法

  • 自動將常規函數轉換成Promise,返回值也是一個Promise對象

  • 只有async函數內部的異步操做執行完,纔會執行then方法指定的回調函數

  • 異步函數內部可使用await

async function name([param[, param[, ... param]]]) { statements }
name: 函數名稱。
param:  要傳遞給函數的參數的名稱
statements: 函數體語句。
返回值: 返回的Promise對象會以async function的返回值進行解析,或者以該函數拋出的異常進行回絕。

image.png

await語法

  • await 放置在Promise調用以前,await 強制後面點代碼等待,直到Promise對象resolve,獲得resolve的值做爲await表達式的運算結果

  • await只能在async函數內部使用,用在普通函數裏就會報錯
[return_value] = await expression;

expression:  一個 Promise  對象或者任何要等待的值。

返回值:返回 Promise 對象的處理結果。若是等待的不是 Promise 對象,則返回該值自己。

image.png

錯誤處理

在async函數裏,不管是Promise reject的數據仍是邏輯報錯,都會被默默吞掉,因此最好把await放入try{}catch{}中,catch可以捕捉到Promise對象rejected的數據或者拋出的異常

function timeout(ms) {

  return new Promise((resolve, reject) => {

    setTimeout(() => {reject('error')}, ms);  //reject模擬出錯,返回error

  });

}

async function asyncPrint(ms) {

  try {

     console.log('start');

     await timeout(ms);  //這裏返回了錯誤

     console.log('end');  //因此這句代碼不會被執行了

  } catch(err) {

     console.log(err); //這裏捕捉到錯誤error

  }

}

asyncPrint(1000);

若是不用try/catch的話,也能夠像下面這樣處理錯誤(由於async函數執行後返回一個promise)

function timeout(ms) {

  return new Promise((resolve, reject) => {

    setTimeout(() => {reject('error')}, ms);  //reject模擬出錯,返回error

  });

}

async function asyncPrint(ms) {

  console.log('start');

  await timeout(ms)

  console.log('end');  //這句代碼不會被執行了

}

asyncPrint(1000).catch(err => {

    console.log(err); // 從這裏捕捉到錯誤

});

若是你不想讓錯誤中斷後面代碼的執行,能夠提早截留住錯誤,像下面

function timeout(ms) {

  return new Promise((resolve, reject) => {

    setTimeout(() => {

        reject('error')

    }, ms);  //reject模擬出錯,返回error

  });

}

async function asyncPrint(ms) {

  console.log('start');

  await timeout(ms).catch(err => {  // 注意要用catch

console.log(err) 

  })

  console.log('end');  //這句代碼會被執行

}

asyncPrint(1000);

使用場景

多個await命令的異步操做,若是不存在依賴關係(後面的await不依賴前一個await返回的結果),用Promise.all()讓它們同時觸發

function test1 () {
    return new Promise((resolve, reject) => {

        setTimeout(() => {

            resolve(1)

        }, 1000)

    })

}

function test2 () {

    return new Promise((resolve, reject) => {

        setTimeout(() => {

            resolve(2)

        }, 2000)

    })

}

async function exc1 () {

    console.log('exc1 start:',Date.now())

    let res1 = await test1();

    let res2 = await test2(); // 不依賴 res1 的值

    console.log('exc1 end:', Date.now())

}

async function exc2 () {

    console.log('exc2 start:',Date.now())

    let [res1, res2] = await Promise.all([test1(), test2()])

    console.log('exc2 end:', Date.now())

}

exc1();

exc2();

exc1 的兩個並列await的寫法,比較耗時,只有test1執行完了纔會執行test2

你能夠在瀏覽器的Console裏嘗試一下,會發現exc2的用Promise.all執行更快一些

image.png

兼容性

image.png

在本身的項目中使用

經過 babel 來使用。

只須要設置 presets 爲 stage-3 便可。

 安裝依賴:

npm install babel-preset-es2015 babel-preset-stage-3 babel-runtime babel-plugin-transform-runtime

修改.babelrc:

 "presets": ["es2015", "stage-3"],

 "plugins": ["transform-runtime"]

    
這樣就能夠在項目中使用 async 函數了。

image.png

相關文章
相關標籤/搜索