在Vue项目上使用异步加载
以SPA的方式构建应用,往往会把所有的代码打包到一起,使得单个js日益庞大。所以我们需要思考一些暂时不用的代码是否可以异步加载,而Vue也提供了这样的能力。
一、使用异步组件
Vue允许以一个工厂函数的方式定义组件,这个工厂函数会收到一个 resolve
回调,这个回调函数会在你从服务器得到组件定义的时候被调用。你也可以调用 reject(reason)
来表示加载失败。这里的 setTimeout
是为了演示用的,如何获取组件取决于你自己。
Vue.component('async-example', function (resolve, reject) {
setTimeout(function () {
// 一些耗时任务
// 向 `resolve` 回调传递组件定义
resolve({
template: 'I am async!'
})
}, 1000)
})
显然以上示例几乎看不出来什么场景需要使用。但这却是使用异步加载的基石。假如我们把setTimeout换成以下这种:
Vue.component('async-example', function (resolve, reject) {
import('path-to-my-component.js').then(component => resolve(component))
.catch(reject)
})
这是不是就是我们想要的吗?这里用到了处于stage 3的dynamic import。
Dynamic
import()
introduces a new function-like form ofimport
that unlocks new capabilities compared to staticimport
.
Dynamic import()现在处于stage 3阶段,相对于import的静态处理方式,import()以一种函数调用的方式来更灵活地加载模块。
二、跟webpack结合
webpack的动态导入也能帮我们解决这个问题。它提供了两个方法:
import()
使用import()动态导入foo,(这里跟dynamic import几乎一样,可以认为是webpack自己的polyfill)
Vue.component('async-component', (resolve) => import('./foo.js')
.then(resolve)
) // import 返回一个promise
Require
Vue.component('async-webpack-example', function (resolve) {
// 这个特殊的 `require` 语法将会告诉 webpack
// 自动将你的构建代码切割成多个包,这些包
// 会通过 Ajax 请求加载
require(['./my-async-component'], resolve)
})
三、在路由层面懒加载
vue-router文档有一节来讲路由懒加载。不过使用的也是上面描述的几种方法,可以对照着看一看。
四、webpack如何实现懒加载
假设我们有如下的代码:
// index.js
const routes = [
{ path: '/foo', component: () => import('./foo') },
{ path: '/bar', component: Bar }
]
// foo.js
export default {
template: "Template Foo
"
}
我们使用下面的配置打包:
module.exports = {
entry: './index.js',
output: {
filename: '[name].bundle.js',
chunkFilename: "[name].bundle.js",
path: __dirname
}
}
打包出来的代码:
// 1.bundle.js 对应 foo.js
(window.webpackJsonp = window.webpackJsonp || []).push([
[1],
[, function (e, o, p) {
"use strict";
p.r(o), o.default = {
template: "Template Foo
"
}
}]
]);
可以看到foo.js
单独打包成了1.bundle.js,加载它的时候,会把代码以函数的方式挂载在window
的webpackJsonp
属性上。
另外查看main.bundle.js
,可以找到它以创建一个script
标签的形式引入1.bundle.js
,另外使用onload
执行代码。