什么是Generator函数
Generator 是 ES6 引入的实现异步操作的一种新方法,在 Generator 出现之前,不管哪种方法,异步操作都是使用回调函数来实现的。只从出现了 Generator 之后,开发人员可以使用同步调用的逻辑来实现异步操作,只要在需要等待的地方,使用 yield 语句放弃运行即可。
Generator函数的语法
Generator 函数的定义,是通过 function *
实现的。对 Generator 函数的调用返回的实际是一个遍历器,随后代码通过使用遍历器的next
方法来获得函数的输出。通过使用 yield
语句来中断 Generator 函数的运行,并且可以返回一个中间结果。每次调用 next
方法,Generator 函数将执行到下一个yield
语句或者是return
语句。
function* list() {
for(var i = 0; i < arguments.length; i++) {
yield arguments[i];
}
return "done.";
}
var o = list(1, 2, 3);
o.next(); // Object {value: 1, done: false}
o.next(); // Object {value: 2, done: false}
o.next(); // Object {value: 3, done: false}
o.next(); // Object {value: "done.", done: true}
o.next(); // Error: Generator has already finished
结合 Promise 使用
利用generator和promise结合使用,让异步的逻辑关系,使用同步的方式书写
function asyncF(name) {
return new Promise(function(resolve){
setTimeout(function(){
resolve('my name is ' + name);
});
});
}
function * fn() {
console.log(yield asyncF('Joh'));
}
let gf = fn();
function exec(gf,value) {
let res = gf.next(value);
if(!res.done) {
if(res.value instanceof Promise) {
res.value.then(function (v) {
exec(gf, v);
})
}else{
exec(gf, res.value);
}
}
}
exec(gf); // my name is Joh
使用场景
Generator是异步解决的一种方案,最大特点则是将异步操作同步化表达出来
function* loadUI() {
showLoadingScreen();
yield loadUIDataAsynchronously();
hideLoadingScreen();
}
var loader = loadUI();
// 加载UI
loader.next()
// 卸载UI
loader.next()
还能利用Generator函数,在对象上实现Iterator接口
function* objectEntries(obj) {
const propKeys = Reflect.ownKeys(obj);
for (const propKey of propKeys) {
yield [propKey, obj[propKey]];
}
}
const myObj = { foo: 3, bar: 7 };
for (const [key,value] of objectEntries(myObj)) {
console.log(`${key}: ${value}`);
}
Reflect.ownKeys() 返回对象所有的属性,不管属性是否可枚举,包括 Symbol。
myObj 原生是不具备 Iterator 接口无法通过 for… of遍历。这边用了 Generator 函数加上了 Iterator 接口,所以就可以遍历 myObj 对象了。