天天看點

async函數

async 函數

async() : Generator 函數的文法糖。(​

​async​

​函數就是将 Generator 函數的星号(​

​*​

​)替換成​

​async​

​,将​

​yield​

​替換成​

​await​

​,僅此而已。)

async和await兩種文法結合可以讓異步代碼像同步代碼一樣

// -傳回值:promise對象
// -promise對象的結果,由async函數執行的傳回值決定      
async function fn() {
    // return 'hello world';
    // return傳回的結果如果不是一個promise類型的對象(例如:字元串),那麼函數的傳回結果就是一個成功的promise對象
    // return傳回的結果是一個promise對象,那麼對象的結果由該對象決定
    return new Promise((resolve, reject) => {
        resolve('成功的資料');
        // reject('失敗的資料');
    })
}
var result = fn();
console.log(result); // Promise {<pending>}      

await

// -await必須寫在async函數中
// -await右側的表達式一般為promise對象
// -await傳回的是promise成功的值
// -await的promise失敗了,就會抛出異常,需要通過try...catch捕獲處理      

​async​

​函數對 Generator 函數的改進,展現在以下四點。

(1)内置執行器。

Generator 函數的執行必須靠執行器,是以才有了​

​co​

​子產品,而​

​async​

​函數自帶執行器。也就是說,​

​async​

​函數的執行,與普通函數一模一樣,隻要一行。

asyncReadFile();      

(2)更好的語義。

​async​

​和​

​await​

​,比起*号和​

​yield​

​,語義更清楚了。​

​async​

​表示函數裡有異步操作,​

​await​

​表示緊跟在後面的表達式需要等待結果。

(3)更廣的适用性。

​co​

​子產品約定,​

​yield​

​指令後面隻能是 Thunk 函數或 Promise 對象,而​

​async​

​函數的​

​await​

​指令後面,可以是 Promise 對象和原始類型的值(數值、字元串和布爾值,但這時會自動轉成立即 resolved 的 Promise 對象)。

(4)傳回值是 Promise。

​async​

​函數的傳回值是 Promise 對象,這比 Generator 函數的傳回值是 Iterator 對象友善多了。你可以用​

​then​

​方法指定下一步的操作。

進一步說,​

​async​

​函數完全可以看作多個異步操作,包裝成的一個 Promise 對象,而​

​await​

​指令就是内部​

​then​

​指令的文法糖。

基本用法

​async​

​函數傳回一個 Promise 對象,可以使用​

​then​

​方法添加回調函數。當函數執行的時候,一旦遇到​

​await​

​就會先傳回,等到異步操作完成,再接着執行函數體内後面的語句。

下面是一個例子,指定多少毫秒後輸出一個值。

function timeout(ms) {
    return new Promise((resolve) => {
        setTimeout(resolve, ms);
    });
}

async function asyncPrint(value, ms) {
    await timeout(ms);
    console.log(value);
}

asyncPrint('hello world', 50);      

上面代碼指定 50 毫秒以後,輸出​

​hello world​

​。

由于​

​async​

​函數傳回的是 Promise 對象,可以作為​

​await​

​指令的參數。是以,上面的例子也可以寫成下面的形式。

async function timeout(ms) {
  await new Promise((resolve) => {
    setTimeout(resolve, ms);
  });
}

async function asyncPrint(value, ms) {
  await timeout(ms);
  console.log(value);
}

asyncPrint('hello world', 50);      

async 函數有多種使用形式。

// 函數聲明
async function foo() {}

// 函數表達式
const foo = async function () {}

// 對象的方法
let obj = {
    async foo() {}
}
obj.foo().then();

// class類的方法
class Storage {
    constructor() {
        this.cachePromise = caches.open('avatars');
    }

    async getAvatar(name) {
        const cache = await this.cachePromise;
        return cache.match(`/avatars/${name}.jpg`);
    }
}

const storage = new Storage();
storage.getAvatar('jake').then(…);

// 箭頭函數
const foo = async () => {};      

注意:

1、async函數在聲明形式上和普通函數沒有差別,函數聲明式,函數表達式,對象方法,class方法和箭頭函數等都可以聲明async函數。

2.任何一個await語句後面的 Promise 對象變為reject狀态,那麼整個async函數都會中斷執行。

3.async函數傳回的 Promise 對象,必須等到内部所有await指令後面的 Promise 對象執行完,才會發生狀态改變,除非遇到return語句或者抛出錯誤。也就是說,隻有async函數内部的異步操作執行完,才會執行then方法指定的回調函數。

文法

​async​

​函數的文法規則總體上比較簡單,難點是錯誤處理機制。

​async​

​函數傳回一個 Promise 對象。

​async​

​函數内部​

​return​

​語句傳回的值,會成為​

​then​

​方法回調函數的參數。

async function foo() {
    return 'hello world';
}
foo().then(v => console.log(v)); // hello world      

​async​

​函數内部抛出錯誤,會導緻傳回的 Promise 對象變為​

​reject​

​狀态。抛出的錯誤對象會被​

​catch​

​方法回調函數接收到。

async function foo() {
    throw new Error('出錯了');
}
foo().then(v => console.log('resolve', v), e => console.log('reject', e)); // reject Error: 出錯了      

Promise對象的狀态變化

繼續閱讀