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,這裡的講解簡單明瞭,我學了很多.
回覆刪除