什么是異步編程
異步編程可以理解為:一個任務(wù)A執(zhí)行到一半時间影,交出自己的執(zhí)行權(quán)并處于“暫吞哦В”狀態(tài)搀罢,轉(zhuǎn)而去執(zhí)行其他的任務(wù)(任務(wù)B)腋粥,然后再條件準(zhǔn)備好時晦雨,再回過頭來執(zhí)行任務(wù)A
在ES6之前,我們一搬會有以下幾種方法來實現(xiàn)異步編程:
- 回掉函數(shù)
- 事件監(jiān)聽
- 發(fā)布/訂閱
- Promise 對象(第三方庫)
但是在ES6時代隘冲,又多了一種異步編程的選擇—— Generator 函數(shù)
Generator 函數(shù)實現(xiàn)一個基本的異步編程
在上一篇中說過闹瞧,Generator 函數(shù)就像一個狀態(tài)機,調(diào)用后返回的遍歷器對象每調(diào)用一次 next() 方法展辞,遍歷器中的狀態(tài)指針才會向后移動到下一個狀態(tài)奥邮,并執(zhí)行下一個狀態(tài)之前的代碼,且不印象后面的代碼罗珍,這就為異步編程提供了良好的條件洽腺,使異步編程的書寫變得如同同步編程一般
function* generator() {
console.log('start')
var res = yield loop();
console.log('end')
}
function loop() {
console.time('loop');
for (var i = 0; i < 1000000000; i ++) {}
console.timeEnd('loop');
}
var g = generator();
g.next();
g.next();
// start
// loop: 540.537ms
// end
上面的代碼中,g 是 generator 方法返回的遍歷器對象覆旱。第一次調(diào)用 next() 方法時蘸朋,會先執(zhí)行 yield 之前的代碼 TASK A,然后執(zhí)行 yield 語句表達式 yield loop()
扣唱,并執(zhí)行耗時函數(shù) loop
第二次調(diào)用 next() 方法時藕坯,會等待第一個 next() 方法完成再執(zhí)行 generator 方法內(nèi)后面的代碼
但是從上面的代碼可以看出,要想用 Generator 函數(shù)實現(xiàn)異步編程噪沙,需要手動地來控制狀態(tài)指針的后移炼彪,在實際工作中會不方便,所以就需要一個方法讓 Generator 函數(shù)能夠自動往后執(zhí)行
基于 Promise 對象自動執(zhí)行 Generator 函數(shù)
現(xiàn)將上面代碼改造成基于 Promise 對象的 Generator 函數(shù)
function* generator() {
console.log('start')
var res = yield loop();
console.log('end')
}
function loop() {
return new Promise(function(resolve, reject) {
try {
console.time('loop');
for (var i = 0; i < 1000000000; i ++) {}
console.timeEnd('loop');
} catch (e) {
reject(e);
}
resolve();
})
}
var g = generator();
g.next().value.then(function() {
g.next();
});
// start
// loop: 2576.482ms
// end
上面代碼中正歼, loop 方法被改造成一個返回 Promise 對象的方法辐马,這樣在調(diào)用第一個 next() 方法時,返回的對象的 value 熟悉就會使一個 Promise 對象局义,可以使用 then() 方法齐疙,再 then() 中再次調(diào)用 next() ,亦可以達到未改動之前的異步效果
基于以上改動后的代碼旭咽,將其最后執(zhí)行的方法封裝成可通用的代碼段
function run(generator){
var g = generator();
function next(data){
var result = g.next(data);
if (result.done) return result.value;
result.value.then(function(data){
next(data);
});
}
next();
}
run(generator);
上面這段代碼中的 data 是需要傳遞的參數(shù),還記得在上一篇中所說的 next() 方法中參數(shù)的意義嗎赌厅?戳鏈接直達上一篇:
ES6學(xué)習(xí)筆記——Generator函數(shù)語法
需要注意的是穷绵,使用上面這段自動執(zhí)行代碼,yield 語句返回的 value 都必須是一個 Promise 對象特愿,否則是無法執(zhí)行的