Generator & Co
Generator¶
什么是生成器¶
- 生成器(Generator)是一个内置迭代器(Iterator)的函数。
- regenerator-runtime,https://www.babeljs.cn/repl。
一个例子¶
function* foo() {
yield 1;
yield 2;
}
it = foo(); // 生成器的执行,返回一个迭代器。
it.next();
it.next();
it.next();
生成器的执行与传参¶
function* bar() {
console.log('执行生成器函数');
var a = yield 'a的值';
console.log('a', a);
var b = yield 'b的值';
console.log('b', b);
}
var it2 = bar();
console.log(it2.next(1));
console.log(it2.next(2));
console.log(it2.next(3));
遇到
yield
就返回参数通过
next
方法传递第一次执行
next
的参数没有意义
类数组对象¶
- 可通过下标访问元素
- 有
length
属性 - 有迭代器生成方法,
[Symbol.iterator]()
执行后返回迭代器 - 满足以上三个条件,就可用
Array.from(arrayLikeObj)
或[...arrayLikeObj]
,转化成数组。
一个类数组对象¶
- 根据类数组对象的条件,简单实现一个类数组对象。
let arrayLikeObj = {
0: 1,
1: 2,
2: 3,
length: 3,
[Symbol.iterator]() {
let index = 0;
return {
next: () => {
return {
value: this[index],
done: this.length <= index++
};
}
};
}
};
// 测试
let a = Array.from(arrayLikeObj);
let b = [...arrayLikeObj];
console.log(a, b);
用生成器改造¶
var arrayLikeObj = {
0: 1,
1: 2,
2: 3,
length: 3,
[Symbol.iterator]: function*() {
for(let i = 0; i < this.length; i++) {
yield this[i];
}
}
};
Co¶
大神的 Co https://github.com/tj/co
场景¶
function* gen() {
let result1 = yield fn(0); // it.next() 调用时才, 往给 result1 赋值
let result2 = yield fn(result1);
return result2;
}
function fn(val) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(val+ 200);
}, 1000);
});
}
STEP1 顺序调用¶
// 测试
var it = gen();
let { value, done } = it.next(); // value 可能时 promise
let resultx = Promise.resolve(value).then(result1 => {
let { value, done } = it.next(result1); // 这里可以递归
return Promise.resolve(value).then(result2 => {
let { value, done } = it.next(result2);
console.log({ value, done });
return Promise.resolve(value); // 递归退出
});
});
resultx.then(x => console.log('x:', x));
STEP2 递归一下¶
function co(gen) {
let it = gen();
function _next(data) {
let { value, done } = it.next(data);
if (done) {
return Promise.resolve(value);
}
return Promise.resolve(value).then(data => _next(data));
}
return _next(undefined);
}
co(gen).then(y => console.log('y:', y));
STEP3 处理 reject¶
function co(gen) {
let it = gen(); // 生成迭代器
return new Promise((resolve, reject) => {
function _next(data) {
let { value, done } = it.next(data);
if (done) {
resolve(value); // 递归退出
return; // 不再往下执行
}
Promise.resolve(value).then(data => _next(data), reject);
}
_next(undefined);
});
}
co(gen).then(
y => console.log('y:', y),
r => console.log('err', r)
);
async/await¶
- 基于 generator & co 的语法糖
语法糖¶
async function gen2() {
let result1 = await fn(0); // it.next() 调用时才, 往给 result1 赋值
let result2 = await fn(result1);
return result2;
}
gen2().then(z => console.log('z:', z));
babel 编译¶
- Source Code
async function f() {
return await 1000;
}
- After Babel
"use strict";
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
try {
var info = gen[key](arg);
var value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
Promise.resolve(value).then(_next, _throw);
}
}
function _asyncToGenerator(fn) {
return function() {
var self = this,
args = arguments;
return new Promise(function(resolve, reject) {
var gen = fn.apply(self, args);
function _next(value) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
}
function _throw(err) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
}
_next(undefined);
});
};
}
function f() {
return _f.apply(this, arguments);
}
function _f() {
_f = _asyncToGenerator(
/*#__PURE__*/ regeneratorRuntime.mark(function _callee() {
return regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch ((_context.prev = _context.next)) {
case 0:
_context.next = 2;
return 1000;
case 2:
return _context.abrupt("return", _context.sent);
case 3:
case "end":
return _context.stop();
}
}
}, _callee);
})
);
return _f.apply(this, arguments);
}
_asyncToGenerator 就相当于 co 函数;
regeneratorRuntime 库是用来编译 function* 这类生成器代码的。