generator的工作原理

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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值