async函式

weixin_34124651發表於2018-08-24

async

要理解 async 先要掌握 Promise 的概念,瞭解 Promise 請戳我

async 函式是什麼?一句話,它就是 Genervator 函式的語法糖。

一個 Genervator 函式,依次讀取兩個檔案。

const fs = require('fs');

const readFile = function(fileName) {
    return new Promise((resolve, reject) => {
        fs.readFile(fileName, (error, data) => {
            if (error) return reject(error);
            reslove(data);
        })
    })
}

const gen = function* () {
    const f1 = yield readFile('/etc/fstab');
    const f2 = yield readFile('/etc/shells');
    console.log(f1.toString());
    console.log(f2.toString());
}

改寫成 async 函式。

const asyncReadFile = async function() {
    // 一旦遇到 await 就先返回,等到非同步操作完成再繼續執行函式體後面的語句
    const f1 = await readFile('/etc/fstab');
    const f2 = await readFile('/etc/shells');
    console.log(f1.toString());
    console.log(f2.toString());
}

async 函式返回的是一個 Promise 物件。進一步說,async 函式完全可以看作多個非同步操作,包裝成的一個 Promise 物件,而內部的 await 命令就是內部 then 的語法糖。

// async 返回一個 Promise 物件
async function f() {
    return 'hello world';
}

// .then 呼叫 Promise 物件
f().then(v => console.log(v));
// "hello world"

async 內部丟擲的異常會導致 Promise 物件變成 reject 的狀態,能夠被 catch 捕獲。

async function f() {
    throw new Error('出錯了');
}

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

await

正常情況下,await 命令後面是一個 Promise 物件。如果不是,會被轉換成一個立即 resolve 的 Promise 物件。

async funciton () {
    return await 123;
}

f().then(v => console.log(v));
// 123

只要 await 語句後面的 Promise 變成 reject,那麼整個 async 函式都會中斷執行。

async function f() {
    await Promise.reject('出錯了');
    await Promise.reslove('hello world'); // 不會執行
}

如果需要避免這個問題,可以是用 try...catch

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

f()
.then(v => console.log(v))
// hello world

案例: 按順序完成非同步操作

實際的開發中,經常遇到一組非同步操作需要按順序完成。比如,以此遠端讀取一組 URL,然後按照讀取順序依次輸出。

async function loginOrder(urls) {
    // 併發讀取遠端URL
    const textPromises = urls.map(async url => {
        const response = await fetch(url);
        return response.text();
    })

    // 按次序輸出
    for (const textPromise of textPromises) {
        console.log(await textPromise);
    }
}

參考

相關文章