問題場景
在大型單頁面應用中,處于對性能的考慮和首屏加載速度的要求,我們一般都會使用webpack的代碼分割和vue-router的路由懶加載功能将我們的代碼分成一個個子產品,并且隻在需要的時候才從伺服器加載一個子產品。
但是這種解決方案也有其問題,當網絡環境較差時,我們去首次通路某個路由子產品,由于加載該子產品的資源需要一定的時間,那麼該段時間内,我們的應用就會處于無響應的狀态,使用者體驗極差。
解決方案
這種情況,我們一方面可以縮小路由子產品代碼的體積,靜态資源使用cdn存儲等方式縮短加載時間,另一方面則可以路由元件上使用異步元件,顯示loading和error等狀态,使使用者能夠得到清晰明了的操作回報。
Vue官方文檔-動态元件&異步元件
具體實作
- 聲明方法,基于Vue動态元件工廠函數來傳回一個Promise對象
/**
* 處理路由頁面切換時,異步元件加載過渡的處理函數
* @param {Object} AsyncView 需要加載的元件,如 import('@/components/home/Home.vue')
* @return {Object} 傳回一個promise對象
*/
function lazyLoadView (AsyncView) {
const AsyncHandler = () => ({
// 需要加載的元件 (應該是一個 `Promise` 對象)
component: AsyncView,
// 異步元件加載時使用的元件
loading: require('@/components/public/RouteLoading.vue').default,
// 加載失敗時使用的元件
error: require('@/components/public/RouteError.vue').default,
// 展示加載時元件的延時時間。預設值是 200 (毫秒)
delay: ,
// 如果提供了逾時時間且元件加載也逾時了,
// 則使用加載失敗時使用的元件。預設值是:`Infinity`
timeout:
});
return Promise.resolve({
functional: true,
render (h, { data, children }) {
return h(AsyncHandler, data, children);
}
});
}
- 引入路由
const helloWorld = () => lazyLoadView(import('@/components/helloWorld'))
- vue-router中使用
routes: [
{
path: '/helloWorld',
name: 'helloWorld',
component: helloWorld
}
]
至此,改造已經完成,當你首次加載某一個元件的資源時(可以将網速調為 slow 3g,效果更明顯),就會顯示你在loading元件的内容,而當超出逾時時間仍未加載完成該元件時,那麼将顯示error元件的内容(建議error元件盡量簡單,因為當處于低速網絡或者斷網情況下時,error元件内的圖檔資源等有可能出現無法加載的問題)