摘要:在最近開發(fā)的一個(gè)里,初始化一個(gè)較重的頁面竟然用了,這讓我開始重視的初始化性能,并最終優(yōu)化到,這篇文章分享我的優(yōu)化思路。初始化時(shí),會(huì)對(duì)做改造,在現(xiàn)代瀏覽器里,這個(gè)過程實(shí)際上挺快的,但仍然有優(yōu)化空間。
原文: https://github.com/Coffcer/Bl...
前言一般來說,你不需要太關(guān)心vue的運(yùn)行時(shí)性能,它在運(yùn)行時(shí)非常快,但付出的代價(jià)是初始化時(shí)相對(duì)較慢。在最近開發(fā)的一個(gè)Hybrid APP里,Android Webview初始化一個(gè)較重的vue頁面竟然用了1200ms ~ 1400ms,這讓我開始重視vue的初始化性能,并最終優(yōu)化到200 ~ 300ms,這篇文章分享我的優(yōu)化思路。
性能瓶頸在哪里?先看一下常見的vue寫法:在html里放一個(gè)app組件,app組件里又引用了其他的子組件,形成一棵以app為根節(jié)點(diǎn)的組件樹。
而正是這種做法引發(fā)了性能問題,要初始化一個(gè)父組件,必然需要先初始化它的子組件,而子組件又有它自己的子組件。那么要初始化根標(biāo)簽
這個(gè)結(jié)果顯然不是我們要的,更好的結(jié)果是頁面可以從上到下按順序流式渲染,這樣可能總體時(shí)間增長了,但首屏?xí)r間縮減,在用戶看來,頁面打開速度就更快了。
要實(shí)現(xiàn)這種渲染模式,我總結(jié)了下有3種方式實(shí)現(xiàn)。第3種方式是我認(rèn)為最合適的,也是我在項(xiàng)目中實(shí)際使用的優(yōu)化方法。
第一種:不使用根組件這種方式非常簡單,例如:
拋棄了根組件
異步組件在官方文檔已有說明,使用非常簡單:
new Vue({ components: { A: { /*component-config*/ }, B (resolve) { setTimeout(() => { resolve({ /*component-config*/ }) }, 0); } } })
這里組件是一個(gè)異步組件,會(huì)等到手動(dòng)調(diào)用resolve函數(shù)時(shí)才開始初始化,而父組件
我們利用setTimeout(fn, 0)將的初始化放在隊(duì)列最后,結(jié)果就是頁面會(huì)在初始化完后立刻顯示,然后再顯示。如果你的頁面有幾十個(gè)組件,那么把非首屏的組件全設(shè)成異步組件,頁面顯示速度會(huì)有明顯的提升。
你可以封裝一個(gè)簡單的函數(shù)來簡化這個(gè)過程:
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):
還是按照上面的異步組件做法,這時(shí)候就需要考慮把哪些組件設(shè)成異步的了。如果把A、B、C都設(shè)成異步的,那結(jié)果就是3個(gè)
這是我推薦的一種做法,簡單有效。還是那個(gè)結(jié)構(gòu),我們給要延遲渲染的組件加上v-if:
new Vue({ data: { showB: false, showC: false }, created () { // 顯示B setTimeout(() => { this.showB = true; }, 0); // 顯示C setTimeout(() => { this.showC = true; }, 0); } });
這個(gè)示例寫起來略顯啰嗦,但它已經(jīng)實(shí)現(xiàn)了我們想要的順序渲染的效果。頁面會(huì)在A組件初始化完后顯示,然后再按順序渲染其余的組件,整個(gè)頁面渲染方式看起來是流式的。
有些人可能會(huì)擔(dān)心v-if存在一個(gè)編譯/卸載過程,會(huì)有性能影響。但這里并不需要擔(dān)心,因?yàn)?b>v-if是惰性的,只有當(dāng)?shù)谝淮沃禐閠rue時(shí)才會(huì)開始初始化。
這種寫法看起來很麻煩,如果我們能實(shí)現(xiàn)一個(gè)類似v-if的組件,然后直接指定多少秒后渲染,那就更好了,例如:
一個(gè)簡單的指令即可,不需要js端任何配合,并且可以用在普通dom上面,Nice!
在vue里,類似v-if和v-for這種是terminal指令,會(huì)在指令內(nèi)部編譯組件。如果你想要自己實(shí)現(xiàn)一個(gè)terminal指令,需要加上terminal: true,例如:
Vue.directive("lazy", { terminal: true, bind () {}, update () {}, unbind () {} });
這是vue在1.0.19+新增的功能,由于比較冷門,文檔也沒有特別詳細(xì)的敘述,最好的方式是參照著v-if和v-for的源碼來寫。
我已經(jīng)為此封裝了一個(gè)terminal指令,你可以直接使用:
https://github.com/Coffcer/vu...
除了組件上的優(yōu)化,我們還可以對(duì)vue的依賴改造入手。初始化時(shí),vue會(huì)對(duì)data做getter、setter改造,在現(xiàn)代瀏覽器里,這個(gè)過程實(shí)際上挺快的,但仍然有優(yōu)化空間。
Object.freeze()是ES5新增的API,用來凍結(jié)一個(gè)對(duì)象,禁止對(duì)象被修改。vue 1.0.18+以后,不會(huì)對(duì)已凍結(jié)的data做getter、setter轉(zhuǎn)換。
如果你確保某個(gè)data不需要跟蹤依賴,可以使用Object.freeze將其凍結(jié)。但請(qǐng)注意,被凍結(jié)的是對(duì)象的值,你仍然可以將引用整個(gè)替換調(diào)??聪旅胬樱?/p>
{{ item.value }}
new Vue({ data: { // vue不會(huì)對(duì)list里的object做getter、setter綁定 list: Object.freeze([ { value: 1 }, { value: 2 } ]) }, created () { // 界面不會(huì)有響應(yīng) this.list[0].value = 100; // 下面兩種做法,界面都會(huì)響應(yīng) this.list = [ { value: 100 }, { value: 200 } ]; this.list = Object.freeze([ { value: 100 }, { value: 200 } ]); } })后記
vue 1.0+ 的組件其實(shí)不算輕量,初始化一個(gè)組件包括依賴收集、轉(zhuǎn)換等過程,但其實(shí)有些是可以放在編譯時(shí)提前完成的。vue 2.0+ 已經(jīng)在這方面做了不少的改進(jìn):分離了編譯時(shí)和運(yùn)行時(shí)、提供函數(shù)組件等,可以預(yù)見,vue 2.0的性能將有很大的提升。
v-lazy-component: https://github.com/Coffcer/vu...
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/90975.html
摘要:工程實(shí)踐立足實(shí)踐,提示實(shí)際水平內(nèi)聯(lián)函數(shù)與性能很多關(guān)于性能優(yōu)化的文章都會(huì)談及內(nèi)聯(lián)函數(shù),其也是常見的被詬病為拖慢性能表現(xiàn)的元兇之一不過本文卻是打破砂鍋問到底,論證了內(nèi)聯(lián)函數(shù)并不一定就會(huì)拖慢性能,過度的性能優(yōu)化反而會(huì)有損于應(yīng)用性能。 showImg(https://segmentfault.com/img/remote/1460000011481413?w=1240&h=825); 前端每周...
摘要:我的目標(biāo)是使本系列成為關(guān)于應(yīng)用程序性能的完整指南。代碼分割就是將應(yīng)用程序分割成這些延遲加載的塊。總結(jié)延遲加載是提高應(yīng)用程序性能并減少其大小的最佳方法之一。在本系列的下一部分中,我將向您展示如何使用和路由來分割應(yīng)用程序代碼。 當(dāng)移動(dòng)優(yōu)先(mobile-first)的方式逐漸成為一種標(biāo)準(zhǔn),而不確定的網(wǎng)絡(luò)環(huán)境因素應(yīng)該始終是我們考慮的一點(diǎn),因此保持讓應(yīng)用程序快速加載變得越來越困難。在本系列文章...
摘要:現(xiàn)在,我們將更深入地研究,并學(xué)習(xí)用于分割應(yīng)用程序最實(shí)用的模式。本系列文章基于對(duì)性能優(yōu)化過程的學(xué)習(xí)。路徑時(shí)才被下載。為了便于理解,文件名稱并不是由生成的真實(shí)名稱。接下來,我們將學(xué)習(xí)其他部分和單獨(dú)的組件也能夠從主文件分割出來并延遲加載。 在前一篇文章中,我們學(xué)習(xí)了什么是代碼分割,它是如何與 Webpack 一起工作的,以及如何在Vue應(yīng)用程序中使用延遲加載?,F(xiàn)在,我們將更深入地研究,并學(xué)習(xí)...
摘要:靜態(tài)模塊不能被取消注冊(cè)也不能延遲注冊(cè),并且在初始化后不能更改靜態(tài)模塊的結(jié)構(gòu)不是狀態(tài)。為此,我們將在路由對(duì)應(yīng)的組件中加載模塊,而不是在中導(dǎo)入并注冊(cè)它。能代碼分割模塊是一個(gè)強(qiáng)大的工具。 在前一部分,我們學(xué)習(xí)了足夠強(qiáng)大的模式,可以顯著提高應(yīng)用程序的性能 - 按每個(gè)路由分割代碼。雖然按路由分割代碼非常有用,但是在用戶訪問我們的站點(diǎn)后,仍然有很多代碼是不需要的。在本系列的這一部分中,我們將重點(diǎn)關(guān)...
摘要:發(fā)布是由團(tuán)隊(duì)開源的,操作接口庫,已成為事實(shí)上的瀏覽器操作標(biāo)準(zhǔn)。本周正式發(fā)布,為我們帶來了,,支持自定義頭部與腳部,支持增強(qiáng),兼容原生協(xié)議等特性變化。新特性介紹日前發(fā)布了大版本更新,引入了一系列的新特性與提升,本文即是對(duì)這些變化進(jìn)行深入解讀。 showImg(https://segmentfault.com/img/remote/1460000012940044); 前端每周清單專注前端...
閱讀 3835·2021-11-24 09:39
閱讀 3753·2021-11-22 12:07
閱讀 1105·2021-11-04 16:10
閱讀 798·2021-09-07 09:59
閱讀 1902·2019-08-30 15:55
閱讀 935·2019-08-30 15:54
閱讀 724·2019-08-29 14:06
閱讀 2475·2019-08-27 10:54