记一次首屏加载优化过程-动态路由提升加载速度

背景

之前分别从原生层面以及 H5 层面对 HTML 的加载过程进行了分析,确定出加载的耗时主要出现在渲染阶段,但是页面本身并不复杂,dom 的结构也很简单,应该渲染很快才对,所以又通过 chrome 的 timeline 来进行更详细的分析开发文档,结果如下图,可以确定出在一次加载过程中主要的耗时在 JS 的运算上面。

js 加载耗时

由此可以引发出一些思考,因为用来做分析的页面本身很简单,没有很多的 js 加载才对。经过分析应该是随着 react 工程增大,路由逐渐变多,经过打包以后多个路由的js打包在了一块所以即使只加载一个路由,也会加载很多其他的东西。

现有路由

现在林林总总路由加起来有二十多个。经过打包以后的js大小有2M多。这就势必拖慢了加载的速度,因为Android进行js运算是很耗时的,在不考虑优化 js 逻辑相关的代码前,使用动态路由技术来对代码进行分离,做到按需加载应该能够提高加载速度。

   <Route path="/" component={WaterIndex} />
    <Route path="/AddWaterMeter" component={AddWaterMeter} />
    <Route path="/ConfirmMeter" component={ConfirmMeter} />

    ...

    <Route path="/FeedbackList" component={FeedbackList} />
    <Route path="/PaymentHelp" component={PaymentHelp} />
  </Router>

动态路由

原理就是将当前的代码在打包过程中分拆成多个小的包,在用户浏览过程中进行按需加载。示例代码

Webpack 配置

首先在 webpack.config.js 的 output 内加上 chunkFilename

output: {
    path: path.join(__dirname, '/../dist/assets'),
    filename: 'app.js',
    publicPath: defaultSettings.publicPath,
    // 添加 chunkFilename
    chunkFilename: '[name].[chunkhash:5].chunk.js',
},

name 是在代码里为创建的 chunk 指定的名字,如果代码中没指定则 webpack 默认分配 id 作为 name。chunkhash 是文件的 hash 码,这里只使用前五位。

路由配置

之前的路由就像上面配置的一样,现在修改成如下的样子

const AddWaterMeter = (location, callback) => {
  require.ensure([], require => {
    callback(null, require('./views/AddWaterMeter').default)
  }, 'AddWaterMeter')
}

const WaterMeterList = (location, callback) => {
  require.ensure([], require => {
    callback(null, require('./views/WaterMeterList').default)
  }, 'WaterMeterList')
}

const ConfirmMeter = (location, callback) => {
  require.ensure([], require => {
    callback(null, require('./views/ConfirmMeter').default)
  }, 'ConfirmMeter')
}

ReactDOM.render(
  <Router
    history={hashHistory}
    render={applyRouterMiddleware(useScroll())}
  >
    <Route path="/" Component={WaterIndex}>
      <Route path="AddWaterMeter" Component={AddWaterMeter} />
      <Route path="ConfirmMeter" getComponent={ConfirmMeter} />
      <Route path="WaterMeterList" getComponent={WaterMeterList} />

      ...

      <Route path="FeedbackList" getComponent={FeedbackList} />
      <Route path="PaymentHelp" getComponent={PaymentHelp} />
    </Route>
  </Router>,
  document.getElementById('app')
)

history 不变,将创建的路由传递进去。有几个属性的说明

  • path

    匹配路由,和之前的定义一样

  • getComponent

    对应于以前的 component 属性,但是这个方法是异步的,也就是当路由匹配时,才会调用这个方法。

    这里面有个 require.ensure 方法

    require.ensure(dependencies, callback, chunkName)

    这是 webpack 提供的方法,这也是按需加载的核心方法。第一个参数是依赖,第二个是回调函数,第三个就是上面提到的 chunkName,用来指定这个 chunk file 的 name。

这里有可能会有一个异常:

The root route must render a single element

这是因为 module.exports 和 ES6 里的 export default 有区别。

如果是使用 es6 的写法,也就是你的组件都是通过 export default 导出的,那么在 getComponent 方法里面需要加入 .default。
如果是使用 CommonJS 的写法,也就是通过 module.exports 导出的,那就无须加 .default 了。

优化结果

经过上面的一通操作,再来看一下页面的加载速度,首先是可以明显的感知到速度变快。通过 timeline 来检测一下

优化结果

可以看到,速度提升了1s,对产品体验来说是一个很大的提升。

参考文档:

猜你喜欢

转载自blog.csdn.net/u011494285/article/details/80480581