-
Notifications
You must be signed in to change notification settings - Fork 4.7k
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
ES6 系列之 Babel 将 Generator 编译成了什么样子 #102
Labels
Comments
写的牛逼,补充下下面的情况: function* helloWorldGenerator() {
const a = yield 'hello';
return a;
}
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var regenerator_runtime_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! regenerator-runtime/runtime */ "./node_modules/regenerator-runtime/runtime.js");
/* harmony import */ var regenerator_runtime_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(regenerator_runtime_runtime__WEBPACK_IMPORTED_MODULE_0__);
var _marked =
/*#__PURE__*/
regeneratorRuntime.mark(helloWorldGenerator);
function helloWorldGenerator() {
var a;
return regeneratorRuntime.wrap(function helloWorldGenerator$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
_context.next = 2;
return 'hello';
case 2:
a = _context.sent; // 补充: context 上面还有个比较重要的属性是 sent
return _context.abrupt("return", a);
case 4:
case "end":
return _context.stop();
}
}
}, _marked, this);
} |
regeneratorRuntime.wrap 函数里的 while (1) 是何用 |
同问,感觉没有啥用 |
目前猜测有点类似于事件循环,一直在做监听 |
没看懂🤣 |
那个while(1) 是怎么停止的啊 也没个break |
有return啊 |
把while(1)去掉了,上面的代码也是可以正常运行的。。可能是考虑以后扩展吧。。 |
# for free
to join this conversation on GitHub.
Already have an account?
# to comment
前言
本文就是简单介绍下 Generator 语法编译后的代码。
Generator
我们打印下执行的结果:
Babel
具体的执行过程就不说了,我们直接在 Babel 官网的 Try it out 粘贴上述代码,然后查看代码被编译成了什么样子:
猛一看,好像编译后的代码还蛮少的,但是细细一看,编译后的代码肯定是不能用的呀,
regeneratorRuntime
是个什么鬼?哪里有声明呀?mark
和wrap
方法又都做了什么?难道就不能编译一个完整可用的代码吗?
regenerator
如果你想看到完整可用的代码,你可以使用 regenerator,这是 facebook 下的一个工具,用于编译 ES6 的 generator 函数。
我们先安装一下 regenerator:
然后新建一个 generator.js 文件,里面的代码就是文章最一开始的代码,我们执行命令:
regenerator --include-runtime generator.js > generator-es5.js
我们就可以在 generator-es5.js 文件看到编译后的完整可用的代码。
而这一编译就编译了 700 多行…… 编译后的代码可以查看 generator-es5.js
总之编译后的代码还蛮复杂,我们可以从中抽离出大致的逻辑,至少让简单编译的那段代码能够跑起来。
mark 函数
简单编译后的代码第一段是这样的:
我们查看完整编译版本中 mark 函数的源码:
这其中又涉及了 GeneratorFunctionPrototype 和 Gp 变量,我们也查看下对应的代码:
这段代码构建了一堆看起来很复杂的关系链,其实这是参照着 ES6 规范构建的关系链:
图中
+@@toStringTag:s = 'Generator'
的就是 Gp,+@@toStringTag:s = 'GeneratorFunction'
的就是 GeneratorFunctionPrototype。构建关系链的目的在于判断关系的时候能够跟原生的保持一致,就比如:
为了简化起见,我们可以把 Gp 先设置为一个空对象,不过正如你在上图中看到的,next()、 throw()、return() 函数都是挂载在 Gp 对象上,实际上,在完整的编译代码中,确实有为 Gp 添加这三个函数的方法:
为了简单起见,我们将整个 mark 函数简化为:
wrap 函数
除了设置关系链之外,mark 函数的返回值 genFun 还作为了 wrap 函数的第二个参数传入:
我们再看下 wrap 函数:
所以当执行
var hw = helloWorldGenerator();
的时候,其实执行的是 wrap 函数,wrap 函数返回了 generator,generator 是一个对象,原型是outerFn.prototype
,outerFn.prototype
其实就是genFun.prototype
,genFun.prototype
是一个空对象,原型上有 next() 方法。所以当你执行
hw.next()
的时候,执行的其实是 hw 原型的原型上的 next 函数,next 函数执行的又是 hw 的 _invoke 函数:innerFn 就是 wrap 包裹的那个函数,其实就是 helloWordGenerato$ 函数,呐,就是这个函数:
而 context 你可以直接理解为这样一个全局对象:
每次
hw.next
的时候,就会修改 next 和 prev 属性的值,当在 generator 函数中 return 的时候会执行 abrupt,abrupt 中又会执行 complete,执行完 complete,因为this.next = end
的缘故,再执行就会执行 stop 函数。我们来看下 makeInvokeMethod 函数:
基本的执行过程就不分析了,我们重点看第三次执行
hw.next()
的时候:第三次执行
hw.next()
的时候,其实执行了我们在 invoke 函数中构建了一个 record 对象:
而在
innerFn.call(self, context)
中,因为 _context.next 为 4 的缘故,其实执行了:而在 abrupt 中,我们又构建了一个 record 对象:
然后执行了
this.complete(record)
,在 complete 中,因为
record.type === "return"
然后返回了全局对象 ContinueSentinel,其实就是一个全局空对象。
然后在 invoke 函数中,因为
record.arg === ContinueSentinel
的缘故,没有执行后面的 return 语句,就直接进入下一个循环。于是又执行了一遍
innerFn.call(self, context)
,此时_context.next
为 end, 执行了_context.stop()
, 在 stop 函数中:所以最终返回的值为:
之后,我们再执行 hw.next() 的时候,因为 state 已经是 'completed' 的缘故,直接就返回
{ value: undefined, done: true}
不完整但可用的源码
当然这个过程,看文字理解起来可能有些难度,不完整但可用的代码如下,你可以断点调试查看具体的过程:
ES6 系列
ES6 系列目录地址:https://github.com/mqyqingfeng/Blog
ES6 系列预计写二十篇左右,旨在加深 ES6 部分知识点的理解,重点讲解块级作用域、标签模板、箭头函数、Symbol、Set、Map 以及 Promise 的模拟实现、模块加载方案、异步处理等内容。
如果有错误或者不严谨的地方,请务必给予指正,十分感谢。如果喜欢或者有所启发,欢迎 star,对作者也是一种鼓励。
The text was updated successfully, but these errors were encountered: