千家信息网

ES6 Babel怎么编译Generator

发表于:2026-11-02 作者:千家信息网编辑
千家信息网最后更新 2026年11月02日,本篇内容主要讲解"ES6 Babel怎么编译Generator",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"ES6 Babel怎么编译Generator"
千家信息网最后更新 2026年11月02日ES6 Babel怎么编译Generator

本篇内容主要讲解"ES6 Babel怎么编译Generator",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"ES6 Babel怎么编译Generator"吧!

Generator

function* helloWorldGenerator() {  yield 'hello';  yield 'world';  return 'ending';}

我们打印下执行的结果:

var hw = helloWorldGenerator();console.log(hw.next()); // {value: "hello", done: false}console.log(hw.next()); // {value: "world", done: false}console.log(hw.next()); // {value: "ending", done: true}console.log(hw.next()); // {value: undefined, done: true}

Babel

具体的执行过程就不说了,我们直接在 Babel 官网的 Try it out 粘贴上述代码,然后查看代码被编译成了什么样子:

/** * 我们就称呼这个版本为简单编译版本吧 */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,    this  );}

猛一看,好像编译后的代码还蛮少的,但是细细一看,编译后的代码肯定是不能用的呀,regeneratorRuntime是个什么鬼?哪里有声明呀?mark 和 wrap 方法又都做了什么?

难道就不能编译一个完整可用的代码吗?

regenerator

如果你想看到完整可用的代码,你可以使用 regenerator ,这是 facebook 下的一个工具,用于编译 ES6 的 generator 函数。

我们先安装一下 regenerator:

npm install -g regenerator

然后新建一个 generator.js 文件,里面的代码就是文章最一开始的代码,我们执行命令:

regenerator --include-runtime generator.js > generator-es5.js

我们就可以在 generator-es5.js 文件看到编译后的完整可用的代码。

而这一编译就编译了 700 多行…… 编译后的代码可以查看 generator-es5.js

总之编译后的代码还蛮复杂,我们可以从中抽离出大致的逻辑,至少让简单编译的那段代码能够跑起来。

mark 函数

简单编译后的代码第一段是这样的:

var _marked = /*#__PURE__*/ regeneratorRuntime.mark(helloWorldGenerator);

我们查看完整编译版本中 mark 函数的源码:

runtime.mark = function(genFun) {  genFun.__proto__ = GeneratorFunctionPrototype;  genFun.prototype = Object.create(Gp);  return genFun;};

这其中又涉及了 GeneratorFunctionPrototype 和 Gp 变量,我们也查看下对应的代码:

function Generator() {}function GeneratorFunction() {}function GeneratorFunctionPrototype() {}...var Gp = GeneratorFunctionPrototype.prototype =  Generator.prototype = Object.create(IteratorPrototype);GeneratorFunction.prototype = Gp.constructor = GeneratorFunctionPrototype;GeneratorFunctionPrototype.constructor = GeneratorFunction;GeneratorFunctionPrototype[toStringTagSymbol] =  GeneratorFunction.displayName = "GeneratorFunction";

这段代码构建了一堆看起来很复杂的关系链,其实这是参照着 ES6 规范 构建的关系链:

图中 +@@toStringTag:s = 'Generator' 的就是 Gp,+@@toStringTag:s = 'GeneratorFunction' 的就是 GeneratorFunctionPrototype。

构建关系链的目的在于判断关系的时候能够跟原生的保持一致,就比如:

function* f() {}var g = f();console.log(g.__proto__ === f.prototype); // trueconsole.log(g.__proto__.__proto__ === f.__proto__.prototype); // true

为了简化起见,我们可以把 Gp 先设置为一个空对象,不过正如你在上图中看到的,next()、 throw()、return() 函数都是挂载在 Gp 对象上,实际上,在完整的编译代码中,确实有为 Gp 添加这三个函数的方法:

// 117 行function defineIteratorMethods(prototype) {  ["next", "throw", "return"].forEach(function(method) {    prototype[method] = function(arg) {      return this._invoke(method, arg);    };  });}// 406 行defineIteratorMethods(Gp);

为了简单起见,我们将整个 mark 函数简化为:

runtime.mark = function(genFun) {  var generator = Object.create({    next: function(arg) {      return this._invoke('next', arg)    }  });  genFun.prototype = generator;  return genFun;};

wrap 函数

除了设置关系链之外,mark 函数的返回值 genFun 还作为了 wrap 函数的第二个参数传入:

function helloWorldGenerator() {  return regeneratorRuntime.wrap(    function helloWorldGenerator$(_context) {      ...    },    _marked,    this  );}

我们再看下 wrap 函数:

function wrap(innerFn, outerFn, self) {  var generator = Object.create(outerFn.prototype);  var context = new Context([]);  generator._invoke = makeInvokeMethod(innerFn, self, context);  return generator;}

所以当执行 var hw = helloWorldGenerator(); 的时候,其实执行的是 wrap 函数,wrap 函数返回了 generator,generator 是一个对象,原型是 outerFn.prototype, outerFn.prototype 其实就是 genFun.prototype, genFun.prototype 是一个空对象,原型上有 next() 方法。

所以当你执行 hw.next() 的时候,执行的其实是 hw 原型的原型上的 next 函数,next 函数执行的又是 hw 的 _invoke 函数:

generator._invoke = makeInvokeMethod(innerFn, self, context);

innerFn 就是 wrap 包裹的那个函数,其实就是 helloWordGenerato$ 函数,呐,就是这个函数:

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();    }  }}

而 context 你可以直接理解为这样一个全局对象:

var ContinueSentinel = {};var context = {  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;  }};

每次 hw.next 的时候,就会修改 next 和 prev 属性的值,当在 generator 函数中 return 的时候会执行 abrupt,abrupt 中又会执行 complete,执行完 complete,因为 this.next = end 的缘故,再执行就会执行 stop 函数。

我们来看下 makeInvokeMethod 函数:

var ContinueSentinel = {};function makeInvokeMethod(innerFn, self, context) {  var state = 'start';  return function invoke(method, arg) {    if (state === 'completed') {      return { value: undefined, done: true };    }    context.method = method;    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        };      }    }  };}

基本的执行过程就不分析了,我们重点看第三次执行 hw.next() 的时候:

第三次执行 hw.next() 的时候,其实执行了

this._invoke("next", undefined);

我们在 invoke 函数中构建了一个 record 对象:

var record = {  type: "normal",  arg: innerFn.call(self, context)};

而在 innerFn.call(self, context) 中,因为 _context.next 为 4 的缘故,其实执行了:

_context.abrupt("return", 'ending');

而在 abrupt 中,我们又构建了一个 record 对象:

var record = {};record.type = 'return';record.arg = 'ending';

然后执行了 this.complete(record),

在 complete 中,因为 record.type === "return"

this.rval = 'ending';this.method = "return";this.next = "end";

然后返回了全局对象 ContinueSentinel,其实就是一个全局空对象。

然后在 invoke 函数中,因为 record.arg === ContinueSentinel 的缘故,没有执行后面的 return 语句,就直接进入下一个循环。

于是又执行了一遍 innerFn.call(self, context),此时 _context.next 为 end, 执行了 _context.stop(), 在 stop 函数中:

this.done = true;return this.rval; // this.rval 其实就是 `ending`

所以最终返回的值为:

{  value: 'ending',  done: true};

之后,我们再执行 hw.next() 的时候,因为 state 已经是 'completed' 的缘故,直接就返回 { value: undefined, done: true}

不完整但可用的源码

当然这个过程,看文字理解起来可能有些难度,不完整但可用的代码如下,你可以断点调试查看具体的过程:

(function() {  var ContinueSentinel = {};  var mark = function(genFun) {    var generator = Object.create({      next: function(arg) {        return this._invoke("next", arg);      }    });    genFun.prototype = generator;    return genFun;  };  function wrap(innerFn, outerFn, self) {    var generator = Object.create(outerFn.prototype);    var context = {      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;      }    };    generator._invoke = makeInvokeMethod(innerFn, context);    return generator;  }  function makeInvokeMethod(innerFn, context) {    var state = "start";    return function invoke(method, arg) {      if (state === "completed") {        return { value: undefined, done: true };      }      context.method = method;      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.wrap = wrap;  regeneratorRuntime.mark = mark;})();var _marked = 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,    this  );}var hw = helloWorldGenerator();console.log(hw.next());console.log(hw.next());console.log(hw.next());console.log(hw.next());

到此,相信大家对"ES6 Babel怎么编译Generator"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

函数 编译 代码 对象 就是 时候 原型 方法 缘故 过程 全局 版本 复杂 内容 实际 文件 源码 这是 学习 实用 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 华服互联网科技靠谱吗 网络科技有限互联网 广州互联网科技公司 西安互联网科技 礼当家互联网科技 安徽鑫晟辉互联网科技 上游互联网科技 互联网科技公司做什么 深圳前海聚择互联网科技有限公司 宁夏众和广鑫互联网科技有限公司 宁夏科技产业互联网案例 移动互联网年度科技创新 互联网金融科技名词解释 广州千川互联网科技有限公司 云南省自由互联网科技有限公司 浙南科技城互联网大厦招聘 互联网科技收购价值 盐城市攀科互联网科技有限公司 青岛互联网科技园 如何强化互联网金融科技 互联网络科技 厦门中拓互联网络科技有限公司 与互联网科技公司 华脉科技工业互联网产品 科技互联网的估值 梅州GM互联网络科技有限公司 上海同邻互联网科技有限公司规模 万物互联网智能科技 北京天晋互联网科技有限公司 山东蛋芒互联网科技有限公司
0