babel-runtime 对异步代码的影响及解决方案

阅读时长 6 分钟读完

背景

前端开发经常会使用 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 的方式从:

改为:

并在 webpack 中添加 babel-polyfill 的入口:

这样做的好处是,我们只需要在项目的主入口文件中引入 babel-polyfill,其他文件都不需要再次引入,避免了重复代码的问题。同时,使用 babel-polyfill 可以避免出现多个执行上下文的问题,提高了代码的运行性能。

在使用上述方法时,需要注意 babel-polyfill 的体积比 babel-runtime 大,因此要在合适的位置引入,以避免对项目的加载速度产生过大的影响。

示例代码

这里提供一个使用了 babel-runtime 和 babel-polyfill 的示例代码,供读者参考:

-- -------------------- ---- -------
-- ------

--------------------------

----- ----- - ----------------------
----- -- - --------------
----- - - ------------------

------------ -- -
  ----- --- - ----- ----------------------------------------------------
  ----- ---- - ----- -----------

  ----- ------ - ------------- -- ------------
  ----- ------ - -------------- ------

  --------------------
------------ -- --------------------
展开代码

在这段代码中,我们使用了 babel-polyfill,避免了重复代码的问题,并且在 app.js 中使用了 yield 关键字,这是 ES6 中引入的新特性,需要被 babel 转义。

为了支持使用 yield 关键字,我们需要在 index.js 文件中引入 babel-register 模块,它会自动帮我们转义使用了 ES6/ES7 语法的文件。

来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/67c346bb314edc2684d1e4c1

纠错
反馈

纠错反馈