背景
前端开发经常会使用 ES6/ES7 中的异步代码,如 async/await,generator/yield 等。但是这些新特性在现有的浏览器中并不完全支持,需要使用 babel 转译为 ES5 代码才能正常运行。在使用 babel 转译时,建议使用 babel-plugin-transform-runtime 插件来避免代码中出现重复的 polyfill 代码。
问题
然而,使用 babel-plugin-transform-runtime 插件有时会带来意想不到的问题。当我们使用 async/await 或者 generator/yield 时,会发现代码中会出现类似下面的代码:
-- -------------------- ---- ------- --- ------------------- - ------------------------------------- --- -------------------- - -------------------------------------------- -------- --------------------------- - ------ --- -- -------------- - --- - - -------- --- -- - -------- --------------------- - ------ -------- -- - --- --- - -------------- ----------- ------ --- ---------------- --------- ------- - -------- --------- ---- - --- - --- ---- - -------------- --- ----- - ----------- - ----- ------- - -------------- ------- - -- ----------- - --------------- - ---- - ------ ------------------------------------ ------- - ------------ ------- -- -------- ----- - ------------- ----- --- - - ------ ------------- --- -- - --- ------- - ------------------------------------------------------------ --------- - --- ---- ------ ------------------------------------------ ------------------ - ----- --- - ------ -------------- - -------------- - ---- -- ------------- - -- ------ ---------------------------------------------------- ---- -- --- - -------------- ------------- - -- ------ ----------- ---- -- ------ ------------------------- --------------- ---- -- ---- ------ ------ ---------------- - - -- -------- ------ ---- ----------------------- ----- - ----------------- ---展开代码
这段代码中使用了 babel-runtime,其中引入了一个名为 _regeneratorRuntime2
的变量。这个变量并没有在代码中定义,而是引入了一个从 babel-runtime/regenerator
模块中导出的对象。在运行时,当代码执行到使用这个变量的地方时,会动态生成委托给 babel-runtime 的代码。
这意味着,我们的代码中存在两个执行上下文:一个运行我们编写的代码,一个运行由 babel-runtime 自动生成的代码。如果我们使用的是多个 babel-plugin-transform-runtime 插件,则在每个插件中都会生成类似的代码,导致代码量的增加,运行时的性能也会受到影响。
解决方案
为了避免以上问题,建议在使用 babel-runtime 时,只使用一个引入了 babel-runtime 的文件,将其他文件改为使用 babel-polyfill。
我们可以把入口文件的引入 babel-runtime 的方式从:
require("babel-runtime/regenerator");
改为:
require("babel-polyfill");
并在 webpack 中添加 babel-polyfill 的入口:
entry: ["babel-polyfill", "./src/index.js"],
这样做的好处是,我们只需要在项目的主入口文件中引入 babel-polyfill,其他文件都不需要再次引入,避免了重复代码的问题。同时,使用 babel-polyfill 可以避免出现多个执行上下文的问题,提高了代码的运行性能。
在使用上述方法时,需要注意 babel-polyfill 的体积比 babel-runtime 大,因此要在合适的位置引入,以避免对项目的加载速度产生过大的影响。
示例代码
这里提供一个使用了 babel-runtime 和 babel-polyfill 的示例代码,供读者参考:
-- -------------------- ---- ------- -- ------ -------------------------- ----- ----- - ---------------------- ----- -- - -------------- ----- - - ------------------ ------------ -- - ----- --- - ----- ---------------------------------------------------- ----- ---- - ----- ----------- ----- ------ - ------------- -- ------------ ----- ------ - -------------- ------ -------------------- ------------ -- --------------------展开代码
// index.js require("babel-register"); require("./app");
在这段代码中,我们使用了 babel-polyfill,避免了重复代码的问题,并且在 app.js 中使用了 yield 关键字,这是 ES6 中引入的新特性,需要被 babel 转义。
为了支持使用 yield 关键字,我们需要在 index.js 文件中引入 babel-register 模块,它会自动帮我们转义使用了 ES6/ES7 语法的文件。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/67c346bb314edc2684d1e4c1