1、async 函數是 Generator 函數的語法糖。前文有一個 Generator 函數,依次讀取兩個文件。
var fs = require('fs'); var readFile = function (fileName) { return new Promise(function (resolve, reject) { fs.readFile(fileName, function(error, data) { if (error) reject(error); resolve(data); }); }); }; var gen = function* () { var f1 = yield readFile('/etc/fstab'); var f2 = yield readFile('/etc/shells'); console.log(f1.toString()); console.log(f2.toString()); };
寫成async
函數,就是下面這樣。
var asyncReadFile = async function () { var f1 = await readFile('/etc/fstab'); var f2 = await readFile('/etc/shells'); console.log(f1.toString()); console.log(f2.toString()); };
async
函數就是將 Generator 函數的星號(*
)替換成async
,將yield
替換成await
,僅此而已。
2、async
函數對 Generator 函數的改進,體現在以下四點。
- 內置執行器。
async
函數自帶執行器。也就是說,async
函數的執行,與普通函數一模一樣,只要一行。var result = asyncReadFile();
上面的代碼調用了
asyncReadFile
函數,然后它就會自動執行,輸出最后結果。這完全不像 Generator 函數,需要調用next
方法 - 更好的語義。
async
和await
,比起星號和yield
,語義更清楚了。async
表示函數里有異步操作,await
表示緊跟在后面的表達式需要等待結果。 - 更廣的適用性。
yield
命令后面只能是 Thunk 函數或 Promise 對象,而async
函數的await
命令后面,可以是Promise 對象和原始類型的值(數值、字符串和布爾值,但這時等同於同步操作)。 - 返回值是 Promise。
async
函數的返回值是 Promise 對象,這比 Generator 函數的返回值是 Iterator 對象方便多了。你可以用then
方法指定下一步的操作。
進一步說,async
函數完全可以看作多個異步操作,包裝成的一個 Promise 對象,而await
命令就是內部then
命令的語法糖。
3、async
函數返回一個 Promise 對象,可以使用then
方法添加回調函數。當函數執行的時候,一旦遇到await
就會先返回,等到異步操作完成,再接着執行函數體內后面的語句。
async function getStockPriceByName(name) { var symbol = await getStockSymbol(name); var stockPrice = await getStockPrice(symbol); return stockPrice; } getStockPriceByName('goog').then(function (result) { console.log(result); });
函數前面的async
關鍵字,表明該函數內部有異步操作。調用該函數時,會立即返回一個Promise
對象。
4、另一個例子,指定多少毫秒后輸出一個值。
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);
5、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 () => {};