JavaScript 好用的 async 異步函數!
先聲明,async 異步函數是 ECMAScript 第七版(ES7)才被支援的語法和特性,目前 ES7 還沒有被大多數的 JavaScript Engine 所實作,如果你要使用,需要用到 babel 這類工具,先把此程式編譯轉換,讓其可在舊版本 JavaScript Engine 上執行。
如果你覺得以 co 模組來操作 Generator 很好用,你可以想像 async 異步函數就是原生的 co,幾乎是同樣的使用方式,同樣的使用概念,只不過不再需要使用 generator 和 yield 這類語法。如果你是個過不了在函數上有個醜陋「*」符號這一關的人,async 異步函數的使用方式應該會讓你感覺到舒服許多。
什麼是 async 異步函數(async functions)?
異步函數使用方式其實和一般的函數一樣,只不過在這函數之內的程式,可以用 await 的語法去執行並等待異步工作(如:Promise)而不需要使用到骯髒的 callback function。宣告並使用一個 async 異步函數,就是在定義函數時加上「async」,然後直接執行這個函數即可,簡單的範例如下:
async function myAsyncFunc() {
console.log('Hello async functions!');
}
myAsyncFunc();
搭配 Promise 的使用
Promise 通常被大量用來管理非同步的工作,並讓開發者容易管理錯誤拋出等機制,一個典型的 Promise 使用如下:
var task = new Promise(function(resolve, reject) {
// 執行一個非同步的工作,完成後呼叫帶入的 callback
doAsyncTask(function(err) {
// 有問題呼叫 reject,並帶入錯誤值
if (err)
return reject(err);
// 成功呼叫 resolve 並帶入回傳值
resolve('VALUE');
});
});
// 使用 then 去執行並等待工作完成,成功會呼叫 callback,失敗則用 catch 去接收。
task
.then(function(val) {
console.log(val);
})
.catch(function(err) {
console.log(err);
});
如果在「異步函數」中呼叫以 Promise 包裝的工作,可以直接使用 await 語法:
async function myAsyncFunc() {
var val = await task;
console.log(val);
}
myAsyncFunc();
搭配 Thunk 的使用
什麼是 Thunk?簡單來說就是一個處理函數,完成時會呼叫 callback 函數表示完成,實務上最常的用法會在外面包一層函數,創造一個 Closure,一個簡單的 Thunk 如下:
function myThunkFunc(thing) {
return function(done) {
setTimeout(function() {
console.log(thing);
done(null, 'World');
}, 1000);
};
}
異步函數裡面,我們可以這樣使用它:
async function myAsyncFunc() {
var val = await myThunkFunc('Hello');
console.log(val);
}
myAsyncFunc();
等待其他異步函數完成工作
當然,await 除了可以吃 Thunk 和 Promise 之外,也可以處理並等待其他的「異步函數」,如下:
async function anotherAsyncFunc(thing) {
var val = await myThunkFunc(thing);
return val;
}
async function myAsyncFunc() {
var val = await anotherAsyncFunc('Hello');
console.log(val);
}
myAsyncFunc();
錯誤處理
當 Promise 的 reject() 被呼叫,或是 Thunk 的 callback 函數被呼叫時,第一個參數不是 null,就代表這個異步工作是有錯誤發生的,如果要從 await 偵測這些錯誤訊息,需要使用 try-catch 去接這些錯誤訊息。
async function myAsyncFunc() {
try {
var val = await myThunkFunc('Hello');
} catch(e) {
console.log(e);
}
}
myAsyncFunc();
舒服!到處使用異步函數
一旦你熟悉如何使用異步函數,你可以到處使用。其實他就像一般的函數一樣,他可以被當成一個 callback 來使用,像是下面這個例子,就把它當成 Promise 的處理函數:
var task = new Promise(async function(resolve, reject) {
try {
await doAsyncTask();
} catch(e) {
return reject(e);
}
resolve();
});
後記
如果你是原本就在使用 co 模組的人,應該會發現 async/await 根本就是一樣的東西,對你來說根本無痛,唯一有點麻煩的是,目前 JavaScript 仍然還沒有原生支援,需要 babel 一類的編譯器才能使用。但有不少人看重程式碼的簡潔和漂亮,已經大量使用了。
另外提到,Koa 2.0 因為完全採用 async/await 的方式,無限期處於不穩定版本。等到 async/await 被原生支援那一天, Koa 2.0 穩定版就會推出了,相信這一天就快要到來。

非常感謝,正在自學JavaScript,這裡的講解簡單明瞭,我學了很多.
回覆刪除