如何异步加载组件
异步组件加载
我们知道react或者是其他用于写单页应用的框架都是组件化的概念,每个路由每个页面就是一个个大组件,webpack在打包的时候,将所有的文件都打包进一个bundle里面,但是我们往往在a页面的时候不需要加载b页面的东西,理想情况下,用户访问一个页面时,该页面应该只需要加载自己使用到的代码,为了提高性能,webpack支持代码分片,将js代码打包到多个文件中按需加载。 按需加载的方式有两种,一个是 webpack提供的require.ensure(),一个是 ES6提案的import() 下面我们写一个asyncComponent异步加载方法,分别使用这两种方式实现。其实是写了一个高阶组件,高阶组件的理解可以看这篇文章。
webpack提供的require.ensure()
webpack提供了require.ensure(),webpack 在编译时,会静态地解析代码中的 require.ensure(),同时将模块添加到一个分开的 chunk 当中。这个新的 chunk 会被 webpack 通过 jsonp 来按需加载。
// asyncCmponent.js
import React, { Component } from 'react';
export default function asyncComponent (importFunc) {
return class App extends Component {
constructor(props) {
super(props);
this.state = {
component: null
}
};
componentDidMount = () => {
importFunc().then(mod => {
this.setState({
component: mod.default || mod
})
});
}
render = () => {
const C = this.state.component;
return (
C ? <C {...this.props} /> : null
)
}
}
}
调用
import asyncCmponent from './asyncCmponent.js';
const App = asyncCmponent(() => require.ensure([], (require) => require('./App')));
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
打开浏览器,可以看到除了bundle.js还多了个1.js,且bundle的体积被拆分出来了。

ES6提案的import()
es6中我们知道import是用于加载使用export命令定义的模块,import和require的区别在于import是在静态解析阶段执行的,所以它是一个模块之中最早执行的,而require是动态加载的,运行时加载模块,import命令无法取代require的动态加载功能。require到底加载哪一个模块,只有运行时才知道。import命令做不到这一点。因此,有一个提案,建议引入import()函数,完成动态加载。详情请看《es6入门》 import()函数返回的是一个promise。
// 只需修改componentDidMount部分
componentDidMount = () => {
importFunc().then(mod => {
this.setState({
component: mod.default || mod
})
})
}
调用
const App = asyncCmponent(() => import('./App')));
打开浏览器,可以看到同样的效果。boom!!!
很棒!