一竭恬、前序
異步操作是javascript編程的一件麻煩事,麻煩到一直有人提出各種各樣的解決方案蝌麸,試圖解決這個(gè)問(wèn)題。但是從最早的回調(diào)函數(shù)艾疟,到Promise對(duì)象来吩,再到Generator函數(shù),雖每次都有所改進(jìn)蔽莱,卻仍舊讓人感覺(jué)到復(fù)雜弟疆。而相比上述幾種方案,async函數(shù)無(wú)疑是讓我們眼前一亮的解決方案盗冷。
二怠苔、async函數(shù)是什么
一句話(huà)概括,async函數(shù)就是Generator函數(shù)的語(yǔ)法糖仪糖。
const fs = require('fs')
function readFile (fileName) {
return new Promise((resolve, reject) => {
fs.readFile(fileName, (error, data) => {
if (error) {
reject(error)
} else {
resolve(data)
}
})
})
}
/* Generator函數(shù)依次讀取兩個(gè)文件 */
function* gen () {
const f1 = yield readFile('/etc/fstab')
const f2 = yield readFile('/etc/shells')
console.log(f1.toString())
console.log(f2.toString())
}
/* async函數(shù)依次讀取兩個(gè)文件 */
async function asyncReadFile () {
const f1 = await readFile('/etc/fstab')
const f2 = await readFile('/etc/shells')
console.log(f1.toString())
console.log(f2.toString())
}
比較async函數(shù)和generator函數(shù)柑司,可以發(fā)現(xiàn)async函數(shù)就是將generator函數(shù)的星號(hào)(*)替換成了async, 將yield替換成了await, 僅此而已。
三锅劝、async函數(shù)的優(yōu)點(diǎn)
- 內(nèi)置執(zhí)行器
async函數(shù)的執(zhí)行攒驰,與普通函數(shù)一摸一樣,只需一行即可完成鸠天。
let result = asyncReadFile()
-
語(yǔ)義更清楚讼育。
- async: 表示函數(shù)內(nèi)存在異步操作
- await:表示需要等待緊跟在后面的表達(dá)式返回結(jié)果
-
實(shí)用性更廣
- await:緊跟其后的帐姻,可以是Promise對(duì)象稠集,也可以是原始類(lèi)型的值(數(shù)值、字符串饥瓷、布爾值剥纷,但此時(shí)等同于同步操作)
四、async函數(shù)的實(shí)現(xiàn)(了解即可)
async函數(shù)的實(shí)現(xiàn)呢铆,就是將generator函數(shù)和自動(dòng)執(zhí)行器晦鞋,包裝在一個(gè)函數(shù)里。模板如下:
async function fn (args) {
// ...
}
// 等同于 (其中spawn函數(shù)就是自動(dòng)執(zhí)行器)
function fn(args) {
return spawn(function* () {
// ...
})
}
五棺克、async函數(shù)的用法(重點(diǎn))
同generator函數(shù)一樣悠垛,async函數(shù)返回一個(gè)Pormise對(duì)象,故而可以使用then方法添加回調(diào)函數(shù)娜谊。當(dāng)async函數(shù)執(zhí)行時(shí)确买,一旦遇到await就會(huì)先返回等到觸發(fā)的異步操作完成,才會(huì)接著執(zhí)行函數(shù)體后面的語(yǔ)句纱皆。
/* 示例一: 獲取股票報(bào)價(jià) */
async function getStockPriceByName(name) {
var symbol = await getStockSymbol(name);
var stockPrice = await getStockPrice(symbol);
return stockPrice;
}
getStockPriceByName('goog').then(function (result){
console.log(result);
});
上面的示例湾趾,函數(shù)前面的async關(guān)鍵字芭商,表明該函數(shù)內(nèi)有異步操作。調(diào)用該函數(shù)時(shí)會(huì)立即返回一個(gè)Promise對(duì)象搀缠。
/* 示例二: 指定n毫秒后輸出一個(gè)值 */
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毫秒后,會(huì)輸出“hello world”
六艺普、注意點(diǎn)
await命令后面的Promise對(duì)象簸州,運(yùn)行結(jié)果可能時(shí)rejected,故而建議:最好將await命令放在try...catch代碼塊中
await命令只能用在async函數(shù)內(nèi)歧譬,若用在普通函數(shù)中就會(huì)報(bào)錯(cuò)