回調(diào)函數(shù) ===> Promise 對象 ===> Generator 函數(shù)
JavaScript 的 async/await
async 和 await 在干什么
async 是“異步”的簡寫,而 await 可以認(rèn)為是 async wait 的簡寫。
async 用于申明一個 function 是異步的膳音,而 await 用于等待一個異步方法執(zhí)行完成卫旱。
await 只能出現(xiàn)在 async 函數(shù)中芦鳍。
async 起什么作用
async function testAsync() {
return "hello async";
}
const result = testAsync();
console.log(result);
——輸出的是一個 Promise 對象各拷。
c:\var\test> node --harmony_async_await .
Promise { 'hello async' }
async 函數(shù)返回的是一個 Promise 對象形病。
參考文檔: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/async_function
async 函數(shù)(包含函數(shù)語句磷脯、函數(shù)表達(dá)式蛾找、Lambda表達(dá)式)會返回一個 Promise 對象,如果在函數(shù)中 return
一個直接量赵誓,async 會把這個直接量通過 Promise.resolve()
封裝成 Promise 對象打毛。
async 函數(shù)返回的是一個 Promise 對象柿赊,所以在最外層不能用 await 獲取其返回值的情況下,我們當(dāng)然應(yīng)該用原來的方式:then()
鏈來處理這個 Promise 對象幻枉,就像這樣
testAsync().then(v => {
console.log(v); // 輸出 hello async
});
Generator 生成器函數(shù)
顧名思義碰声,它是一個生成器,它也是一個狀態(tài)機(jī)熬甫,內(nèi)部擁有值及相關(guān)的狀態(tài)胰挑,生成器返回一個迭代器Iterator對象,我們可以通過這個迭代器椿肩,手動地遍歷相關(guān)的值瞻颂、狀態(tài),保證正確的執(zhí)行順序郑象。
如上代碼贡这,定義了一個showWords的生成器函數(shù),調(diào)用之后返回了一個迭代器對象(即show)
調(diào)用next方法后厂榛,函數(shù)內(nèi)執(zhí)行第一條yield語句盖矫,輸出當(dāng)前的狀態(tài)done(迭代器是否遍歷完成)以及相應(yīng)值(一般為yield關(guān)鍵字后面的運算結(jié)果)
每調(diào)用一次next,則執(zhí)行一次yield語句击奶,并在該處暫停辈双,return完成之后,就退出了生成器函數(shù)正歼,后續(xù)如果還有yield操作就不再執(zhí)行了.
換言之辐马,next 方法的作用是分階段執(zhí)行 Generator 函數(shù)。每次調(diào)用 next 方法局义,會返回一個對象喜爷,表示當(dāng)前階段的信息( value 屬性和 done 屬性)。value 屬性是 yield 語句后面表達(dá)式的值萄唇,表示當(dāng)前階段的值檩帐;done 屬性是一個布爾值,表示 Generator 函數(shù)是否執(zhí)行完畢另萤,即是否還有下一個階段湃密。
function* showWords() {
yield 'one';
yield 'two';
return 'three';
}
var show = showWords();
調(diào)用 Generator 函數(shù)丽涩,會返回一個內(nèi)部指針(即遍歷器 )g 入挣。這是 Generator 函數(shù)不同于普通函數(shù)的另一個地方色冀,即執(zhí)行它不會返回結(jié)果造垛,返回的是指針對象。調(diào)用指針 g 的 next 方法纵苛,會移動內(nèi)部指針(即執(zhí)行異步任務(wù)的第一段)铣卡,指向第一個遇到的 yield 語句奢赂,上例是執(zhí)行到 'three'為止铺厨。
Generator 函數(shù)缎玫,依次讀取兩個文件硬纤。
var fs = require('fs');
var gen = function* (){
var f1 = yield readFile('/etc/fstab');
var f2 = yield readFile('/etc/shells');
console.log(f1.toString());
console.log(f2.toString());
};
寫成 async 函數(shù),就是下面這樣赃磨。
var asyncReadFile = async function (){
var f1 = await readFile('/etc/fstab');
var f2 = await readFile('/etc/shells');
console.log(f1.toString());
console.log(f2.toString());
};
其中筝家,readFile 函數(shù)定義如下:
var readFile = function (fileName){
return new Promise(function (resolve, reject){
fs.readFile(fileName, function(error, data){
if (error) reject(error);
resolve(data);
});
});
};
一比較就會發(fā)現(xiàn),async 函數(shù)就是將 Generator 函數(shù)的星號(*)替換成 async邻辉,將 yield 替換成 await溪王,僅此而已。
async 函數(shù)的實現(xiàn)
async 函數(shù)的實現(xiàn)恩沛,就是將 Generator 函數(shù)和自動執(zhí)行器在扰,包裝在一個函數(shù)里缕减。
async function fn(args){
// ...
}
等同于
function fn(args){
return spawn(function*() {
// ...
});
}
所有的 async 函數(shù)都可以寫成上面的第二種形式雷客,其中的 spawn 函數(shù)就是自動執(zhí)行器。
下面給出 spawn 函數(shù)的實現(xiàn)桥狡,基本就是前文自動執(zhí)行器的翻版搅裙。
function spawn(genF) {
return new Promise(function(resolve, reject) {
var gen = genF();
function step(nextF) {
try {
var next = nextF();
} catch(e) {
return reject(e);
}
if(next.done) {
return resolve(next.value);
}
Promise.resolve(next.value).then(function(v) {
step(function() { return gen.next(v); });
}, function(e) {
step(function() { return gen.throw(e); });
});
}
step(function() { return gen.next(undefined); });
});
}
async 函數(shù)是非常新的語法功能,新到都不屬于 ES6裹芝,而是屬于 ES7部逮。目前,它仍處于提案階段嫂易,但是轉(zhuǎn)碼器 Babel 和 regenerator 都已經(jīng)支持兄朋,轉(zhuǎn)碼后就能使用。
yield與異步
函數(shù)在遇到y(tǒng)ield后暫停運行怜械,我們可以在需要的地方使用next讓它繼續(xù)運行颅和。并且必要時可以使用next傳入?yún)?shù)。
yield 關(guān)鍵字用來暫停和繼續(xù)一個生成器函數(shù)缕允。我們可以在需要的時候控制函數(shù)的運行峡扩。
yield 關(guān)鍵字使生成器函數(shù)暫停執(zhí)行,并返回跟在它后面的表達(dá)式的當(dāng)前值障本。與return類似教届,但是可以使用next方法讓生成器函數(shù)繼續(xù)執(zhí)行函數(shù)yield后面內(nèi)容,直到遇到y(tǒng)ield暫图菟或return返回或函數(shù)執(zhí)行結(jié)束案训。
for…of
for…of循環(huán)可以自動遍歷Generator函數(shù)時生成的Iterator對象。
function* ge() {
yield '1';
yield '2';
yield '3';
return '4';
}
for(let v of ge()){
alert(V); // 1 2 3 4
}
Kotlin 開發(fā)者社區(qū)
國內(nèi)第一Kotlin 開發(fā)者社區(qū)公眾號粪糙,主要分享强霎、交流 Kotlin 編程語言、Spring Boot猜旬、Android脆栋、React.js/Node.js倦卖、函數(shù)式編程、編程思想等相關(guān)主題椿争。