原文地址:regeneratorgit
搜了一圈,关于 Generator
基本都是在讲用法,但不多说起到其工做原理,也就是“协程”。但又由于这东西咱们直接或间接的天天都在使用,因而准备专门写一篇文章来说讲这个github
Callback
Deferred
也在各大开源库能看到踪迹,如 qiankun{ value: any, done: boolean }
来判断状态asyncGeneratorStep
和 _asyncToGenerator
,其实它就是自动执行功能async function a() {} function* b() {} // babel 编译后 function asyncGeneratorStep(gen, resolve, reject, _next, ...) { // 调用 gen 的 next 或 throw 方法 var info = gen[key](arg); var value = info.value; if (info.done) { resolve(value); } else { // 递归执行 Promise.resolve(value).then(_next, _throw); } } function _asyncToGenerator(fn) { return function () { return new Promise(function (resolve, reject) { // 获取 generator 对象 var gen = fn.apply(self, arguments); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } // 初始化执行 next _next(undefined); }); }; }
function* gen() {} const gObj = gen(); gObj.next(); gObj.return();
function*
语法来定义,它是 GeneratorFunction 的实例Object.getPrototypeOf(gen).constructor // GeneratorFunction {prototype: Generator, ...}
const GeneratorFunction = Object.getPrototypeOf(gen).constructor;
Function
是一个级别的,能够传参来建立函数,如const gen = new GeneratorFunction('a', 'yield a * 2'); const gObj = gen(10); gObj.next().value // 20
正片开始,代码示例:api
let num = 0; async function gen() { num = num + (await wait(10)); await 123; await foo(); return num; } function wait(num: number) { return new Promise((resolve) => setTimeout(() => resolve(num), 600)); } async function foo() { await "literal"; } await gen(); console.log("regenerator: res", num);
若是你对原型链和继承有所遗忘的话,建议先看下这篇 prototype&extendspromise
class GeneratorFunction {} // GeneratorFunction 的 prototype 很通用,单独拎出来 class GeneratorFunctionPrototype { static [Symbol.toStringTag] = "GeneratorFunction"; // 实现 iterator protocol next(args) {} return(args) {} throw(args) {} // 实现 iterable protocol [Symbol.iterator]() { return this; } } // 相互引用 GeneratorFunctionPrototype.constructor = GeneratorFunction; GeneratorFunction.prototype = GeneratorFunctionPrototype; // 做用不大,设置 prototype 便可 class Generator {} Generator.prototype = GeneratorFunctionPrototype.prototype;
switch case + context 记录参数
实现function _callee$(_context) { while (1) { switch (_context.next) { case 0: // await wait(10) _context.next = 3; return wait(10); case 3: // await 123 _context.next = 7; return 123; case 7: _context.next = 9; // await foo() return foo(); case "end": return _context.stop(); } } }
_asyncToGenerator
咱们以前说了,就是自动执行,这其实和 co(markFn)
无异。另外一方面你能够推断出 regeneratorRuntime.mark
函数返回的其实就是 polyfill 的 Generatorfunction _foo() { _foo = _asyncToGenerator( regeneratorRuntime.mark(function _callee2() { return regeneratorRuntime.wrap(function _callee2$(_context2) { switch (_context2.next) { case 0: _context2.next = 2; return "literal"; case "end": return _context2.stop(); } }, _callee2); }) ); return _foo.apply(this, arguments); }
{ value: "literal", done: true }
做为了 mark 函数的返回值,并交给 _asyncToGenerator 使用,它如何使用的呢,固然是 promise.then(next)
{ value: fooRetValue, done: false }
,继续 nextfunction mark(genFn: () => void) { return _inheritsLoose(genFn, GeneratorFunctionPrototype); } function _inheritsLoose(subClass, superClass) { Object.setPrototypeOf(subClass, superClass); subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; return subClass; }
type GeneratorMethod = "next" | "return" | "throw"; class GeneratorFunctionPrototype { // set by wrap fn private _invoke: (method: GeneratorMethod, args) => { value: any, done: boolean }; // 注意这是原型方法哦 next(args) { return this._invoke("next", args); } return(args) { return this._invoke("return", args); } throw(args) { return this._invoke("throw", args); } }
function wrap(serviceFn) { // 依然借用 GeneratorFunctionPrototype 的能力 const generator = new Generator(); const context = new Context(); let state = GenStateSuspendedStart; // 实现 _invoke generator._invoke = function invoke(method: GeneratorMethod, args) { context.method = method; context.args = args; if (method === "next") { // 记录上下文参数 context.sent = args; } else if (method === "throw") { throw args } else { context.abrupt("return", args); } // 执行业务上的代码 const value = serviceFn(context); state = context.done ? GenStateCompleted : GenStateSuspendedYield; return { value, done: context.done }; }; return generator; }
class Context { next: number | string = 0; sent: any = undefined; method: GeneratorMethod = "next"; args: any = undefined; done: boolean = false; value: any = undefined; stop() { this.done = true; return this.value; } abrupt(type: "return" | "throw", args) { if (type === "return") { this.value = args; this.method = "return"; this.next = "end"; } else if (type === "throw") { throw args; } } }
最后一点,可能各位用得少,但缺了的话,Generator 是不完整的babel
async function a() { const res = await b(); } async function b() { await 1; await 'str'; return { data: 'lawler', msg: 'ok' }; }
function gen$(_context) { switch (_context.next) { case 0: _context.next = 7; return wait(10); case 7: // 传递 foo generator object 给 gen 的 context return _context.delegateYield(foo(), "t2", 8); case "end": return _context.stop(); } }
generator._invoke = function invoke(method, args) { context.method = method; // yield* genFn 时使用,循环返回 genFn 迭代的结果,直到 return while (true) { const delegate = context.delegate; if (delegate) { const delegateResult = maybeInvokeDelegate(delegate, context); if (delegateResult) { if (delegateResult === empty) continue; // 传出内部迭代结果 { value, done } return delegateResult; } } } if (method === "next") {} }
regenerator
作的事情还不少,如 throw error、yield* gen() 时各类情况的处理以及其余方便的 api,喜欢的自行 dive in 吧