generator的工作原理
使用示例useage
例子:基本用法
// 定义
function* test(args){
console.log('start-->>>',args);
yield 'test-1';
console.log('args-->>>',args);
yield 'test-2';
return 'test-3';
}
// 像普通函数一样执行
const tt = test('ccc');
// 第一次调用输出 start语句
// 返回一个对象 {value:'test-1',done:false}
tt.next();
// 第二次调用输出args语句
// 返回 {value:'test-2',done:false}
tt.next();
// 第三次调用返回 {value:'test-3',done:true}
例子:在对象中使用
let obj = {
*test(){
yield 'obj test'
return 'a';
}
}
例子:构造函数中使用
特性总结feature
架构原理architecture
通过babel编译本文开头的例子如下:
"use strict";
require("regenerator-runtime/runtime.js");
var _marked = /*#__PURE__*/regeneratorRuntime.mark(helloWorldGenerator);
function helloWorldGenerator() {
return regeneratorRuntime.wrap(function helloWorldGenerator$(_context) {
while (1) {
// 状态转移函数
switch (_context.prev = _context.next) {
case 0:
_context.next = 2;
return 'hello';
case 2:
_context.next = 4;
return 'world';
case 4:
return _context.abrupt("return", 'ending');
case 5:
case "end":
return _context.stop();
}
}
}, _marked);
}
var hw = helloWorldGenerator();
hw.next('aaa');
整理babel编译出来的结果
const regeneratorRuntime = {
mark:function(genFun){},
wrap:function(innerFn, outerFn, self){}
}
var _marked = regeneratorRuntime.mark(helloWorldGenerator);
function helloWorldGenerator() {
return regeneratorRuntime.wrap(helloWorldGenerator$, _marked, this);
function helloWorldGenerator$(_context){
//*helloWorldGenerator内部的代码
}
}
// 通过本文开头的例子中的控制台输出,即:test.__proto__ = Generator;
// 可以推测regeneratorRuntime提供的方法一定是设置helloWorldGenerator的原型,且原型上一定有next方法(可以是动态添加或者静态设置)
// next方法返回某个函数局部作用域的对象,该对象上有{value,done}两个属性
先假设*helloWorldGenerator的原型Generator为一个空函数,并静态添加一个next方法
function Generator(){}
Generator.prototype.next = function(){}
现在处理next方法返回一个对象,即runtime
(function(){
var record = {
done:false,
value:''// 未知,后面处理
}
function Generator(){}
Generator.prototype.next = function(){
return record;
}
// 一、对外暴露两个api,这俩个方法一定是让*helloWorldGenerator和Generator产生关系的方法
// 即:设置*helloWorldGenerator编译后的helloWorldGenerator的原型为Generator
var regeneratorRuntime = {
mark:function(genFun){
// 设置genFun.prototype.next方法
var generator = Object.create({
next: function (arg) {
// 二、这里动态设置了next方法,并调用原型的_invoke方法,
// 覆盖了上面设置的next方法,所以,this._invoke方法一定返回了对象{value,done}
return this._invoke("next", arg);// 七、makeInvokeMethod内部的invoke方法,即:下次执行时传入的method和arg
},
});
genFun.prototype = generator;
},
wrap:function(innerFn, outerFn, self){
// 三、设置genFun.prototype._invoke方法
var generator = Object.create(outerFn.prototype);
// 四、缓存innerFn和context,innerFn即状态转移函数
generator._invoke = makeInvokeMethod(innerFn, context());
}
}
function context(){
// 五、状态函数
return {
done: false,
method: "next",
next: 0,
prev: 0,
abrupt: function (type, arg) {
var record = {};
record.type = type;
record.arg = arg;
return this.complete(record);
},
complete: function (record, afterLoc) {
if (record.type === "return") {
this.rval = this.arg = record.arg;
this.method = "return";
this.next = "end";
}
return ContinueSentinel;
},
stop: function () {
this.done = true;
return this.rval;
},
};
}
function makeInvokeMethod(innerFn, context){
// 六、*helloWorldGenerator编译后的代码helloWorldGenerator$,即*helloWorldGenerator的函数体
var state = "start";
return function invoke(method, arg){// 七、method下一次执行的方法,下次执行的参数
if (state === "completed") {
return { value: undefined, done: true };
}
context.method = method;// 八、设置context的下次调用的方法和参数
context.arg = arg;
while (true) {
state = "executing";
var record = {
type: "normal",
arg: innerFn.call(self, context),// 九、调用状态转移函数
};
if (record.type === "normal") {
state = context.done ? "completed" : "yield";
if (record.arg === ContinueSentinel) {
continue;
}
return {// 十、返回结果
value: record.arg,
done: context.done,
};
}
}
}
}
window.regeneratorRuntime = regeneratorRuntime;
})()
时序图帮助理解
总结
regeneratorRuntime就是状态模式,context控制状态,*helloWorldGenerator的函数体就是状态转移函数
完成的代码参考
https://blog.csdn.net/weixin_34383618/article/details/88718209