日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > vue >内容正文

vue

Vue 跨平台性能优化十法

發布時間:2024/2/28 vue 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Vue 跨平台性能优化十法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

作者:bartonwang,騰訊 IEG 客戶端開發工程師

Vue 是一套用于構建用戶界面的漸進式的 JavaScript 框架。具有體積小,更高的運行效率,雙向數據綁定,生態豐富、學習成本低等優點,所以 Vue 也被廣泛用在移動端跨平臺框架上。Vue 框架通過數據雙向綁定和虛擬 DOM 技術,幫我們處理了前端開發中最臟最累的 DOM 操作部分, 我們不再需要去考慮如何操作 DOM 以及如何最高效地操作 DOM,但是我們仍然需要去關注 Vue 在跨平臺項目性能方面的優化,使項目具有更高效的性能、更好的用戶體驗。

1. v-for 遍歷必須為 item 添加 key,且避免同時使用 v-if

在列表數據進行遍歷渲染時,需要為每一項 item 設置唯一 key 值,方便 Vue.js 內部機制精準找到該條列表數據。當 state 更新時,新的狀態值和舊的狀態值對比,較快地定位到 diff 。我們在使用的使用經常會使用 index(即數組的下標)來作為 key,但其實這是不推薦的一種使用方法;

舉個例子:

var?list?=?[{id:?1,name:?'test1',},{id:?2,name:?'test2',},{id:?3,name:?'test3',}, ]<div?v-for="(item,?index)?in?list"?:key="index"?>{{item.name}}</div>

在最后一條數據后再加一條數據:

var?list?=?[{id:?1,name:?'test1',},{id:?2,name:?'test2',},{id:?3,name:?'test3',},{id:?4,name:?'我是在最后添加的一條數據',}, ]

此時前三條數據直接復用之前的,新渲染最后一條數據,此時用 index 作為 key,沒有任何問題,在中間插入一條數據:

var?list?=?[{id:?1,name:?'test1',},{id:?4,name:?'我是插隊的那條數據',},{id:?2,name:?'test2',},{id:?3,name:?'test3',}, ]

此時更新渲染數據,通過 index 定義的 key 去進行前后數據的對比,發現:

之前的數據?????????????????????????之后的數據key:?0??index:?0?name:?test1?????key:?0??index:?0?name:?test1key:?1??index:?1?name:?test2?????key:?1??index:?1?name:?我是插隊的那條數據key:?2??index:?2?name:?test3?????key:?2??index:?2?name:?test2key:?3??index:?3?name:?test3

通過上面清晰的對比,發現除了第一個數據可以復用之前的之外,另外三條數據都需要重新渲染。是不是很驚奇,我明明只是插入了一條數據,怎么三條數據都要重新渲染?而我想要的只是新增的那一條數據新渲染出來就行了。最好的辦法是使用數組中不會變化的那一項作為 key 值,對應到項目中,即每條數據都有一個唯一的 id,來標識這條數據的唯一性;

使用 id 作為 key 值,我們再來對比一下向中間插入一條數據,此時會怎么去渲染:

之前的數據???????????????????????????????之后的數據key:?1??id:?1?index:?0?name:?test1?????key:?1??id:?1?index:?0??name:?test1key:?2??id:?2?index:?1?name:?test2?????key:?4??id:?4?index:?1??name:?我是插隊的那條數據key:?3??id:?3?index:?2?name:?test3?????key:?2??id:?2?index:?2??name:?test2key:?3??id:?3?index:?3??name:?test3

現在對比發現只有一條數據變化了,就是 id 為 4 的那條數據,因此只要新渲染這一條數據就可以了,其他都是就復用之前的。

總結:所以一句話,key 的作用主要是為了高效的更新虛擬 DOM。另外 vue 中在使用相同標簽名元素的過渡切換時,也會使用到 key 屬性,其目的也是為了讓 vue 可以區分它們,否則 vue 只會替換其內部屬性而不會觸發過渡效果。

v-for 遍歷避免同時使用 v-if,v-for 比 v-if 優先級高,如果每一次都需要遍歷整個數組,將會影響速度,尤其是當之需要渲染很小一部分的時候,必要情況下應該替換成 computed 屬性。

2. 長列表性能優化

Vue 會通過 Object.defineProperty 對數據進行劫持,來實現視圖響應數據的變化,然而有些時候我們的組件就是純粹的數據展示,不會有任何改變,我們就不需要 Vue 來劫持我們的數據,在大量數據展示的情況下,這能夠很明顯的減少組件初始化的時間,那如何禁止 Vue 劫持我們的數據呢?可以通過 Object.freeze 方法來凍結一個對象,一旦被凍結的對象就再也不能被修改了。

export?default?{data:?()?=>?({users:?{}}),async?created()?{const?users?=?await?axios.get("/api/users");this.users?=?Object.freeze(users);} };

3. vue 組件中的 data 是函數而不是對象

export?default?{data()?{//?data是一個函數,data:?function()?{}的簡寫return?{//?頁面要初始化的數據name:?'barton',};}, };

而非如下所示:

export?default?{data:?{//?data是一個對象name:?'barton',}, };

當一個組件被定義,data 必須聲明為返回一個初始數據對象的函數,因為組件可能被用來創建多個實例,復用在多個頁面。

如果 data 是一個純碎的對象,則所有的實例將共享引用同一份 data 數據對象,無論在哪個組件實例中修改 data,都會影響到所有的組件實例。如果 data 是函數,每次創建一個新實例后,調用 data 函數,從而返回初始數據的一個全新副本數據對象。這樣每復用一次組件,會返回一份新的 data 數據,類似于給每個組件實例創建一個私有的數據空間,讓各個組件的實例各自獨立,互不影響保持低耦合。

4. Vue 鉤子函數之鉤子事件 hookEvent,監聽組件簡化代碼

用法:

  • 通過 $on(eventName, eventHandler) 偵聽一個事件;

  • 通過 $once(eventName,eventHandler) 一次性偵聽一個事件;

  • 通過 $off(eventName, eventHandler) 停止偵聽一個事件;

  • 通常實現一個定時器的調用與銷毀我可能會以以下方式實現:

    export?default{data(){timer:null??//?需要創建實例},mounted(){this.timer?=?setInterval(()=>{//具體執行內容console.log('1');},1000);}beforeDestory(){clearInterval(this.timer);this.timer?=?null;} }

    這種方法存在的問題是:

    vue 實例中需要有這個定時器的實例,感覺有點多余。創建的定時器代碼和銷毀定時器的代碼沒有放在一起,不容易維護,通常很容易忘記去清理這個定時器。

    使用 監聽beforeDestory生命周期可以避免該問題,并且因為只需要監聽一次,所以使用 $once 進行注冊監聽。

    export?default{methods:{fn(){const?timer?=?setInterval(()=>{console.log('1');},1000);this.$once('hook:beforeDestory',()=>{?//?監聽一次即可clearInterval(timer);timer?=?null;})}} }

    5. 組件懶加載

    在單頁應用中,如果沒有應用懶加載,運用 webpack 打包后的文件將會異常的大,造成進入首頁時,需要加載的內容過多,延時過長,不利于用戶體驗,而運用懶加載則可以將頁面進行劃分,需要的時候加載頁面,可以有效的分擔首頁所承擔的加載壓力,減少首頁加載用時。

    Vue.js 2.0 組件級懶加載方案

    • 支持 組件可見或即將可見時懶加載

    • 支持 組件延時加載

    • 支持 加載真實組件前展示骨架組件,提高用戶體驗

    • 支持 真實組件代碼分包異步加載

    安裝

    npm install @xunlei/vue-lazy-component

    在組件中實現局部注冊組件:

    import?{?component?as?VueLazyComponent?}?from?'@xunlei/vue-lazy-component'export?default?{components:?{'vue-lazy-component':?VueLazyComponent} }

    需要懶加載的組件將其包裹在 vue-lazy-component 中,slot 值為 skeleton 指的是在懶加載過程中顯示的加載狀態組件:

    <vue-lazy-component?:timeout="5000"?tagName="div"><child1?slot="skeleton"?/><child2?/><child3?/><child4?/><child5?/> </vue-lazy-component>

    6. 非響應式數據

    初始化時,vue 會對 data 做 getter、setter 改造。在 Vue 的文檔中介紹數據綁定和響應時,特意標注了對于經過 Object.freeze() 方法的對象無法進行更新響應。

    性能提升對比

    在基于 Vue 的一個 big table benchmark 里,可以看到在渲染一個一個 1000 x 10 的表格的時候,開啟 Object.freeze()前后重新渲染的對比。

    開啟優化之前:

    開啟優化之后:

    在這個例子里,使用了 Object.freeze()比不使用快了 4 倍,為什么 Object.freeze()的性能會更好?

    不使用 Object.freeze()的 CPU 開銷

    使用 Object.freeze()的 CPU 開銷

    對比可以看出,使用了 Object.freeze()之后,減少了 observer 的開銷。

    7. 不要將所有的數據都放到 data 中

    data 中的數據都會增加 getter 和 setter,又會收集 watcher,這樣還占內存。不需要響應式的數據我們可以定義在實例上。

    8. v-for元素綁定事件代理

    事件代理作用主要是 2 個:

  • 將事件處理程序代理到父節點,減少內存占用率

  • 動態生成子節點時能自動綁定事件處理程序到父節點

  • 1、不使用事件代理,每個 span 節點綁定一個 click 事件,并指向同一個事件處理程序

    <div><spanv-for="(item,index)?of?100000":key="index"@click="handleClick">{{item}}</span></div>

    2、不使用事件代理,每個 span 節點綁定一個 click 事件,并指向不同的事件處理程序

    <div><spanv-for="(item,index)?of?100000":key="index"@click="function?()?{}">{{item}}</span></div>

    3、使用事件代理

    <div??@click="handleClick"><spanv-for="(item,index)?of?100000":key="index">{{item}}</span></div>

    可以看到使用事件代理無論是監聽器數量和內存占用率都比前兩者要少,同時對比 3 個圖中監聽器的數量并沒有發現 vue 會自動做事件代理,但是一般給 v-for 綁定事件時,都會讓節點指向同一個事件處理程序(第二種情況可以運行,但是 eslint 會警告),一定程度上比每生成一個節點都綁定一個不同的事件處理程序性能好,但是監聽器的數量仍不會變,所以使用事件代理會更好一點。

    代碼使用:

    <ul?@click="meths"><li?v-for="(item,key)?in?10"?:key="key"?:data-index="key">{{item}}</li></ul>meths(e)?{if?(e.target.nodeName.toLowerCase()?===?'li')?{console.log(e.target.innerHTML)console.log(e.target.dataset)}}

    9. 函數式組件

    函數式組件是無狀態,它無法實例化,沒有任何的生命周期和方法。創建函數式組件也很簡單,只需要在模板添加 functional 聲明即可。一般適合只依賴于外部數據的變化而變化的組件,因其輕量,渲染性能也會有所提高。

    組件需要的一切都是通過 context 參數傳遞。它是一個上下文對象,具體屬性查看文檔。這里 props 是一個包含所有綁定屬性的對象。

    函數式組件:

    10. provide 和 inject 組件通信

    痛點:常用的父子組件通信方式都是父組件綁定要傳遞給子組件的數據,子組件通過 props 屬性接收,一旦組件層級變多時,采用這種方式一級一級傳遞值非常麻煩,而且代碼可讀性不高,不便后期維護。

    vue 提供了 provide 和 inject 幫助我們解決多層次嵌套嵌套通信問題。在 provide 中指定要傳遞給子孫組件的數據,子孫組件通過 inject 注入祖父組件傳遞過來的數據,可以輕松實現跨級訪問父組件的數據。

    provide:是一個對象,或者是一個返回對象的函數。里面呢就包含要給子孫后代的東西,也就是屬性和屬性值。注意:子孫層的 provide 會掩蓋祖父層 provide 中相同 key 的屬性值。

    inject:一個字符串數組,或者是一個對象。屬性值可以是一個對象,包含 from 和 default 默認值,from 是在可用的注入內容中搜索用的 key (字符串或 Symbol),意思就是祖父多層 provide 提供了很多數據, from 屬性指定取哪一個 key default 指定默認值。

    從上面這個例子可以看出,只要在父組件中調用了,那么在這個父組件生效的生命周期內,所有的子組件都可以調用 inject 來注入父組件中的值。

    在使用場景中,肯定是希望父組件的數據一旦發生改變,子孫組件獲取到的也是父組件更新后的數據。那么,怎么實現父組件與子孫組件所綁定的數據動態響應呢?

    -------------------parent.vue---------------------- provide(){return?{//?keyName:?{name:this.name},?//?value?是對象才能實現響應式,也就是引用類型keyName:?this.changeValue?//?通過函數的方式也可以[注意,這里是把函數作為value,而不是this.changeValue()]//?keyName:?'test'?value?如果是基本類型,就無法實現響應式}},data(){return?{name:'張三'}},methods:?{changeValue(){this.name?=?'改變后的名字-李四'}}-------------grandson.vue-----------------inject:['keyName']create(){console.log(this.keyName)?//?改變后的名字-李四 }

    最近其他文章

    一套優雅的 Go 錯誤問題解決方案

    淺談 RocketMQ、Kafka、Pulsar 的事務消息

    總結

    以上是生活随笔為你收集整理的Vue 跨平台性能优化十法的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。