基本定義
Generator是一個迭代器生成函數,其返回值是一個迭代器(Iterator),可用于異步調用。
function* tell() {
console.log('執行a處理');
yield 'a';
console.log('執行b處理');
yield 'b';
console.log('執行c處理');
return 'c';
}
let k = tell();
// 執行next()的時候,會運行到第一個yield為止
console.log(k.next()); // 執行a處理
// {value: "a", done: false}
// 執行next()的時候,會運行到第二個yield為止
console.log(k.next()); // 執行b處理
// {value: "b", done: false}
// 執行next()的時候,會運行到第三個yield為止
console.log(k.next()); // 執行c處理
// {value: "c", done: true}
console.log(k.next()); // {value: undefined, done: true}
常用場景
比如某個事物只有三種狀態(狀態A,狀態B,狀態C),而這三種狀態的變化是 狀態A => 狀態B => 狀態C => 狀態A ,這就是狀態機。Generator特別適用于處理這種狀態機。
// A,B,C三種狀態循環
function* state(){
while(1){
yield 'A';
yield 'B';
yield 'C';
}
}
let status = state();
console.log(status.next()); // {value: "A", done: false}
console.log(status.next()); // {value: "B", done: false}
console.log(status.next()); // {value: "C", done: false}
console.log(status.next()); // {value: "A", done: false}
console.log(status.next()); // {value: "B", done: false}
使用案例
案例1:長輪詢
// 定義一個generator函數,其返回值是一個promise
let ajax = function* () {
yield new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
code: 0
})
}, 1000);
})
}
// 定義一個輪詢函數,當輪詢結果的code!=0時,1秒之后開始下一次輪詢
let pull = function () {
let generator = ajax();
let step = generator.next();
step.value.then((v) => {
if (v.code != 0) {
setTimeout(() => {
console.log('wait');
pull();
}, 1000);
} else {
console.log(v);
}
})
}
pull(); // 執行輪詢
案例2:抽獎
// 抽獎處理
let draw = function (count) {
// 此處省略具體的抽獎邏輯
console.log(`剩余${count}次`);
}
// 根據剩余次數判斷是否執行抽獎處理
let residue = function* (count) {
while (count > 0) {
count--;
yield draw(count);
}
}
// 初始化抽獎次數為5次
let star = residue(5);
// 創建抽獎按鈕
let btn = document.createElement('button');
btn.id = 'start';
btn.textContent = '抽獎';
document.body.appendChild(btn);
// 綁定抽獎事件
document.getElementById('start').addEventListener('click', () => {
star.next();
}, false)
補充:async
- async 函數就是 Generator 函數的語法糖。
// 異步編程
function timeout(ms) {
return new Promise((resolve, reject) => {
setTimeout(resolve, 1000);
})
}
async function asyncPrint(value, ms) {
await timeout(ms).then(() => {
console.log('我是異步處理');
});
console.log(value);
}
asyncPrint('hello world', 1000);
// 執行結果:
// 1秒之后,先打印出"我是異步處理",然后打印出"hello world"
// 普通編程
function timeout(ms) {
return new Promise((resolve, reject) => {
setTimeout(resolve, 1000);
})
}
function asyncPrint(value, ms) {
timeout(ms).then(() => {
console.log('我是異步處理');
});
console.log(value);
}
asyncPrint('hello world', 1000);
// 執行結果:
// 先打印出"hello world"
// 1秒之后,打印出"我是異步處理"