-
Notifications
You must be signed in to change notification settings - Fork 4.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in 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)去掉了,上面的代码也是可以正常运行的。。可能是考虑以后扩展吧。。 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in 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: