前言
成都創(chuàng)新互聯(lián)公司專注骨干網(wǎng)絡(luò)服務(wù)器租用10多年,服務(wù)更有保障!服務(wù)器租用,川西大數(shù)據(jù)中心 成都服務(wù)器租用,成都服務(wù)器托管,骨干網(wǎng)絡(luò)帶寬,享受低延遲,高速訪問。靈活、實現(xiàn)低成本的共享或公網(wǎng)數(shù)據(jù)中心高速帶寬的專屬高性能服務(wù)器。
一般來說,你不需要太關(guān)心vue的運行時性能,它在運行時非??欤冻龅拇鷥r是初始化時相對較慢。在最近開發(fā)的一個Hybrid APP里,Android Webview初始化一個較重的vue頁面竟然用了1200ms ~ 1400ms,這讓我開始重視vue的初始化性能,并最終優(yōu)化到200 ~ 300ms,這篇文章分享我的優(yōu)化思路。
性能瓶頸在哪里?
先看一下常見的vue寫法:在html里放一個app組件,app組件里又引用了其他的子組件,形成一棵以app為根節(jié)點的組件樹。
<body> <app></app> </body>
而正是這種做法引發(fā)了性能問題,要初始化一個父組件,必然需要先初始化它的子組件,而子組件又有它自己的子組件。那么要初始化根標簽<app>,就需要從底層開始冒泡,將頁面所有組件都初始化完。所以我們的頁面會在所有組件都初始化完才開始顯示。
這個結(jié)果顯然不是我們要的,更好的結(jié)果是頁面可以從上到下按順序流式渲染,這樣可能總體時間增長了,但首屏?xí)r間縮減,在用戶看來,頁面打開速度就更快了。
要實現(xiàn)這種渲染模式,我總結(jié)了下有3種方式實現(xiàn)。第3種方式是我認為最合適的,也是我在項目中實際使用的優(yōu)化方法。
第一種:不使用根組件
這種方式非常簡單,例如:
<body> <A></A> <B></B> <C></C> </body>
拋棄了根組件<app>,從而使A、B、C每一個組件初始化完都立刻展示。但根組件在SPA里是非常必要的,所以這種方式只適用小型頁面。
第二種:異步組件
異步組件在官方文檔已有說明,使用非常簡單:
<app> <A></A> <B></B> </app>
new Vue({ components: { A: { /*component-config*/ }, B (resolve) { setTimeout(() => { resolve({ /*component-config*/ }) }, 0); } } })
這里<B>組件是一個異步組件,會等到手動調(diào)用resolve函數(shù)時才開始初始化,而父組件<app>也不必等待<B>先初始化完。
我們利用setTimeout(fn, 0)將<B>的初始化放在隊列最后,結(jié)果就是頁面會在<A>初始化完后立刻顯示,然后再顯示<B>。如果你的頁面有幾十個組件,那么把非首屏的組件全設(shè)成異步組件,頁面顯示速度會有明顯的提升。
你可以封裝一個簡單的函數(shù)來簡化這個過程:
function deferLoad (component, time = 0) { return (resolve) => { window.setTimeout(() => resolve(component), time) }; } new Vue({ components: { B: deferLoad( /*component-config*/ ), // 100ms后渲染 C: deferLoad( /*component-config*/, 100 ) } })
看起來很美好,但這種方式也有問題,考慮下這樣的結(jié)構(gòu):
<app> <title></title> <A></A> <title></title> <B></B> <title></title> <C></C> </app>
還是按照上面的異步組件做法,這時候就需要考慮把哪些組件設(shè)成異步的了。如果把A、B、C都設(shè)成異步的,那結(jié)果就是3個<title>會首先渲染出來,頁面渲染的過程在用戶看來非常奇怪,并不是預(yù)期中的從上到下順序渲染。
第三種:v-if 和 terminal指令
這是我推薦的一種做法,簡單有效。還是那個結(jié)構(gòu),我們給要延遲渲染的組件加上v-if:
<app> <A></A> <B v-if="showB"></B> <C v-if="showC"></C> </app>
new Vue({ data: { showB: false, showC: false }, created () { // 顯示B setTimeout(() => { this.showB = true; }, 0); // 顯示C setTimeout(() => { this.showC = true; }, 0); } });
這個示例寫起來略顯啰嗦,但它已經(jīng)實現(xiàn)了我們想要的順序渲染的效果。頁面會在A組件初始化完后顯示,然后再按順序渲染其余的組件,整個頁面渲染方式看起來是流式的。
有些人可能會擔(dān)心v-if存在一個編譯/卸載過程,會有性能影響。但這里并不需要擔(dān)心,因為v-if是惰性的,只有當?shù)谝淮沃禐閠rue時才會開始初始化。
這種寫法看起來很麻煩,如果我們能實現(xiàn)一個類似v-if的組件,然后直接指定多少秒后渲染,那就更好了,例如:
<app> <A></A> <B v-lazy="0"></B> <C v-lazy="100"></C> </app>
一個簡單的指令即可,不需要js端任何配合,并且可以用在普通dom上面,Nice!
在vue里,類似v-if和v-for這種是terminal指令,會在指令內(nèi)部編譯組件。如果你想要自己實現(xiàn)一個terminal指令,需要加上terminal: true,例如:
Vue.directive('lazy', { terminal: true, bind () {}, update () {}, unbind () {} });
這是vue在1.0.19+新增的功能,由于比較冷門,文檔也沒有特別詳細的敘述,最好的方式是參照著v-if和v-for的源碼來寫。
我已經(jīng)為此封裝了一個terminal指令,你可以直接使用:https://github.com/Coffcer/vu...
其他的優(yōu)化點
除了組件上的優(yōu)化,我們還可以對vue的依賴改造入手。初始化時,vue會對data做getter、setter改造,在現(xiàn)代瀏覽器里,這個過程實際上挺快的,但仍然有優(yōu)化空間。
Object.freeze()
是ES5新增的API,用來凍結(jié)一個對象,禁止對象被修改。vue 1.0.18+以后,不會對已凍結(jié)的data做getter、setter轉(zhuǎn)換。
如果你確保某個data不需要跟蹤依賴,可以使用Object.freeze將其凍結(jié)。但請注意,被凍結(jié)的是對象的值,你仍然可以將引用整個替換調(diào)??聪旅胬樱?/p>
<p v-for="item in list">{{ item.value }}</p>
new Vue({ data: { // vue不會對list里的object做getter、setter綁定 list: Object.freeze([ { value: 1 }, { value: 2 } ]) }, created () { // 界面不會有響應(yīng) this.list[0].value = 100; // 下面兩種做法,界面都會響應(yīng) this.list = [ { value: 100 }, { value: 200 } ]; this.list = Object.freeze([ { value: 100 }, { value: 200 } ]); } })
后記
vue 1.0+ 的組件其實不算輕量,初始化一個組件包括依賴收集、轉(zhuǎn)換等過程,但其實有些是可以放在編譯時提前完成的。vue 2.0+ 已經(jīng)在這方面做了不少的改進:分離了編譯時和運行時、提供函數(shù)組件等,可以預(yù)見,vue 2.0的性能將有很大的提升。
v-lazy-component: https://github.com/Coffcer/vu...
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持創(chuàng)新互聯(lián)。
網(wǎng)頁題目:淺談Vue初始化性能優(yōu)化
網(wǎng)站地址:http://sd-ha.com/article28/psoocp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站建設(shè)、企業(yè)網(wǎng)站制作、軟件開發(fā)、ChatGPT、Google、微信小程序
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)