忘記文檔密碼解除方法 忘記文檔密碼解除方法是什么
2024-08-25
更新時間:2024-08-25 18:04:44作者:佚名
隨著互聯(lián)網(wǎng)的發(fā)展,越來越多的公司都在使用Vue但是隨著項目的越來越大,難免的會帶來一系列的性能問題,筆者也為了這些問題而感到頭疼,也同樣的針對Vue的性能優(yōu)化進(jìn)行學(xué)習(xí),已便在項目之出把性能問題規(guī)避掉,避免沒有必要的返工。
為了方便以后能夠快速的找到相關(guān)學(xué)習(xí)內(nèi)容,在這里做一下記錄,方便以后查看,同時也想把這些內(nèi)容總結(jié)一下希望能夠幫助更多的小伙伴一起學(xué)習(xí),一起成長。Fighting~
這個時候可能會有很多小伙伴說,現(xiàn)在Vue3.0都快發(fā)布了為什么還要優(yōu)化2.0的項目?因為公司80%的項目全是Vue2.0的項目,遷移的話成本太高,所以只能進(jìn)行性能的優(yōu)化調(diào)整。廢話就不多贅述了,直接開始吧。
活用異步組件
Vue-cli打包的時候會把所有依賴的文件打包成一個很大的一個js文件中,當(dāng)用戶瀏覽網(wǎng)頁的時候需要把整個js文件拉取過來,這樣會導(dǎo)致頁面在初始化的時候,頁面會出現(xiàn)長時間的白屏情況,這個問題確實是蠻棘手的。
設(shè)想一下如果在頁面中有很多的功能點(diǎn),每個功能點(diǎn)又對應(yīng)著不同的功能彈窗或者表單,首先第一點(diǎn)頁面中的功能很多,我們不知道用戶想要使用哪個功能,需要彈出哪個彈窗或表單,如果異步組件的情況,Vue-cli在打包的時候會把異步組件單獨(dú)打包成一個文件,當(dāng)用戶使用的才會去加載這個js文件內(nèi)容,這樣無論是首屏的渲染起到了一定的優(yōu)化的作用。
看下官網(wǎng)對于異步組件的說明:
在大型應(yīng)用中,我們可能需要將應(yīng)用分割成小一些的代碼塊,并且只在需要的時候才從服務(wù)器加載一個模塊。為了簡化,Vue允許你以一個工廠函數(shù)的方式定義你的組件,這個工廠函數(shù)會異步解析你的組件定義。Vue 只有在這個組件需要被渲染的時候才會觸發(fā)該工廠函數(shù),且會把結(jié)果緩存起來供未來重渲染。
// 代碼截取自Vue官網(wǎng)Vue.component('async-webpack-example', () => import('./my-async-component'))
Vue官方為了解決組件加載時的等待過長,提供了異步組件加載Loading的異步組件:
// 代碼截取自Vue官網(wǎng)const AsyncComponent = () => ({ // 需要加載的組件 (應(yīng)該是一個 `Promise` 對象) component: import('./MyComponent.vue'), // 異步組件加載時使用的組件 loading: LoadingComponent, // 加載失敗時使用的組件 error: ErrorComponent, // 展示加載時組件的延時時間。默認(rèn)值是 200 (毫秒) delay: 200, // 如果提供了超時時間且組件加載也超時了, // 則使用加載失敗時使用的組件。默認(rèn)值是:`Infinity` timeout: 3000})
使用異步組件需要注意以下幾點(diǎn):
如果只是需要異步的加載一些組件,先加載一部分,再加載一部分,那么就可以直接使用Vue官網(wǎng)的那種寫法直接使用setTimeOut也不是未嘗不可的。如果是點(diǎn)擊加載的話,一定要寫v-if,不然會報錯,說test組件未注冊。v-if是惰性的,只有當(dāng)?shù)谝淮沃禐閠rue時才會開始初始化。初始化減少DOM的渲染
仍然是上面所說的情況,頁面中功能點(diǎn)很多,但是又很多彈窗什么的,其實對于這些彈窗最開始的時候考慮所有的彈窗只使用一個彈窗,為了節(jié)約頁面初始化的渲染,但是在實際開發(fā)過程中,雖然解決了一部分問題,仿佛在開發(fā)過程中并不是那么樂觀,在彈窗內(nèi)部出現(xiàn)了大量的v-if和v-show對于維護(hù)來說太難了。
也有想過使用<component/>組件,但是一個<component/>所承受的壓力可想而知不是一點(diǎn)半點(diǎn)的。但是這個問題仍然是存在的需要得到解決。沒有辦法的情況下,最后使用了兩個flag去控制彈窗的顯示與隱藏。
<template> <div> <el-dialog title="提示" v-if="isRenderDialog" :visible.sync="isShowDialog"></el-dialog> <el-button @click="onShowDialog">Render Dialog</el-button> </div></template><script>export default { data:() => ({ isRenderDialog:false, isShowDialog:false }), methods: { onShowDialog(){ !this.isRenderDialog && (this.isRenderDialog = true); this.$nextTick(() => { this.isShowDialog = true; }) } }}</script>
上述代碼中使用兩個flag值控制Dialog一個是控制Dialog的渲染,一個控制Dialog的顯示,當(dāng)用戶首次進(jìn)入頁面的時候則dialog元素不會被渲染,當(dāng)用戶點(diǎn)擊按鈕,對應(yīng)的Dialog才會被渲染出來,當(dāng)Dialog的DOM渲染完成使用在使用顯示Dialog。
注:在$nextTick中顯示dialog是為了保證dialog的動畫效果,如果不使用$nextTick則dialog就會很生硬的出現(xiàn)。
組件內(nèi)部請求數(shù)據(jù)
大家在做業(yè)務(wù)的時候,可能會有這種情況,當(dāng)點(diǎn)擊按鈕之后,需要獲取到該條數(shù)據(jù)的詳情渲染到彈窗或者側(cè)滑中,這種情況一定不在少數(shù)啦。筆者在開始做這個的時候就是,在點(diǎn)擊的時候直接去獲取點(diǎn)擊的元素的詳情數(shù)據(jù),當(dāng)數(shù)據(jù)返回之后把數(shù)據(jù)放到data中緩存,之后再傳到組件中。
這樣做不是不可行的,也是可以的,這樣就會面臨一個問題,第一點(diǎn)就是當(dāng)彈窗中的渲染的元素過多的情況下,側(cè)滑或者彈窗的動畫效果會很卡,有的時候甚至是不動,瞬間就消失了。
最后經(jīng)過反復(fù)的實驗,把數(shù)據(jù)放到彈窗內(nèi)部組件中去請求,保證彈窗或者側(cè)滑出現(xiàn)的時候內(nèi)置元素較少,當(dāng)數(shù)據(jù)沒有請求回來之前需要把彈框組件內(nèi)的所有元素隱藏,使用loading代替,當(dāng)彈窗或者側(cè)滑關(guān)閉的使用需要把顯示的組件銷毀掉,保證里面的數(shù)據(jù)所占用的內(nèi)存被釋放,這樣對于整體優(yōu)化還是有一些幫助的。
tamplate少計算
由于業(yè)務(wù)情況的復(fù)雜程度,難免會某一個地方添加各種條件的渲染,例如:v-if=”isHide && selectList.length && (isA || isB)”,這里也只是舉一個簡單的例子可能在實際的開發(fā)過程中的情況遠(yuǎn)比這個要復(fù)雜的多,這種表達(dá)式看上去雖然說是可以維護(hù)的,但是長此以往下去就會暴露問題,這樣做是很不利于維護(hù)的。
對于這種情況可以適當(dāng)?shù)氖褂胢ethods或computed封裝成方法,其實這樣做的好處是方柏霓我們判斷相同的表達(dá)式,如果其他的元素也有類似的需求可以直接使用這個方法。
v-for && v-bind:key
在使用v-for循環(huán)過程中,使用:key=”item.id”這樣的代碼對于代碼的性能是很不友好的,因為當(dāng)data數(shù)據(jù)更新的時候,新的狀態(tài)值會和舊的狀態(tài)值做對比,Vue在多diff算法的時候能夠更快的定位到虛擬DOM的元素上。
其實說到這里就需要說明一下key在vue中到底起到一個什么樣的作用,key屬性其實是vue的一個優(yōu)化,上文也說了就是為了更精準(zhǔn)高效的定位到虛擬DOM,相當(dāng)于使用key給數(shù)組中某個預(yù)算綁定到了一起,如果那個key對應(yīng)的數(shù)據(jù)發(fā)生了變化,直接更新對應(yīng)的DOM就可以了。
對于簡短的for來說可以直接使用index作為key但是,如果大型列表的話最好還是不要使用index作為key了。舉個例子,例如數(shù)組刪除了一個元素,那么這個元素后方元素的下標(biāo)全都前移了一位,之前key對應(yīng)的數(shù)據(jù)和dom就會亂了,除非重新匹配key,那就容易產(chǎn)生錯誤。如果重新匹配key,等于全部重新渲染一遍,違背了使用key來優(yōu)化更新dom的初衷。但是如果對于Vue玩的很透的同學(xué)來說可以可以忽略這一條。
Object.freeze
如果對Vue有一定了解的小伙伴都知道Vue是通過Object.defineProperty對數(shù)據(jù)進(jìn)行挾持,來最終實現(xiàn)視圖響應(yīng)數(shù)據(jù)的變化,但是在實際的開發(fā)過程中,頁面中有一部分可能不需要進(jìn)行雙向綁定,只是做單純的渲染,數(shù)據(jù)一旦綁定之后不需要再做出任何改變的時候可以使用Object.freeze對數(shù)據(jù)做解綁。
先介紹以下Object.freeze內(nèi)置函數(shù),用于對接對象,凍結(jié)后的對象不會再被修改,不能對這個對象進(jìn)行添加新屬性, 不能刪除已有屬性,不能修改該對象已有屬性的可枚舉性,可配置性,可寫性.此外凍結(jié)一個對象后該對象的原型也不能進(jìn)行修改。
當(dāng)數(shù)據(jù)量大的時候,這能夠很明顯的減少組件初始化的時間,這里有一個需要注意的點(diǎn)就是一旦被凍結(jié)的對象就再也不能被修改了。但是這里有一個問題需要注意的是,嗒嗒嗒,敲黑板!敲黑板!敲黑板!
雖然Object.freeze在一定程度上能夠幫助我們提升一部分的數(shù)據(jù)性能,但是在使用的時候仍然需要謹(jǐn)慎使用。避免造成數(shù)據(jù)無法響應(yīng)的問題。如果使用Object.freeze這個屬性再次給其對象屬性賦值時,則會拋出錯誤不能分配給對象的只讀屬性*。
用這種方法去提升性能如果數(shù)據(jù)量小的情況是無法感覺出來的。只有數(shù)據(jù)量大的時候,才會感覺到數(shù)據(jù)的明顯變化。
渲染前處理
在渲染數(shù)據(jù)的時候,后端所返回的數(shù)據(jù)和UI設(shè)計圖中所需要的數(shù)據(jù)格式不一致,比如:列表中需要展示一個時間,但是后端返回的是一個時間戳,那么前端就需要對這部分?jǐn)?shù)據(jù)進(jìn)行處理。一般來說處理這種情況有一些辦法,使用函數(shù),使用filter,還有就是在渲染之前把數(shù)據(jù)處理好。
筆者這里比較建議在渲染之前把所有的數(shù)據(jù)處理好,為什么?數(shù)據(jù)渲染之后完成之后才會去執(zhí)行里面的函數(shù)或者是過濾器,這樣會給頁面渲染造成很明顯的額外的負(fù)擔(dān)。如果對Vue3.0了解的同學(xué)可以知道,在Vue3.0中已經(jīng)把filter這個功能已經(jīng)去掉了,推薦使用computed來實現(xiàn)相同相同的效果。
猜測內(nèi)容:可能尤大大也發(fā)現(xiàn)了filter給頁面渲染帶來的額外的負(fù)擔(dān),并沒有對頁面的性能提升起到很大的作用。
functional
不是很多函數(shù)組件都需要方法,Vue中為了表示一個模板應(yīng)該被編譯成一個功能組件,在模板中 添加了functional屬性。如果項目中的所使用的組件不是有狀態(tài)的組件,那么就可以使用functional屬性把這個組件轉(zhuǎn)換成功能組件。
功能組件(不要與Vue的render函數(shù)混淆)是一個不包含狀態(tài)和實例的組件。功能組件是一個沒有狀態(tài)或?qū)嵗慕M件。由于功能組件沒有狀態(tài),因為不需要為Vue的數(shù)據(jù)響應(yīng)之類的東西做初始化動作。功能組件仍然會像出入的props一樣對數(shù)據(jù)更新做出響應(yīng),但是功能組件的自身,由于它不維護(hù)自己的狀態(tài),同時也因此無法知道自己的數(shù)據(jù)是否已經(jīng)發(fā)生了改變。在大型項目中使用功能組件以后,在對于DOM渲染有重大的改進(jìn)。
由于功能組件沒有狀態(tài),因此不需要為Vue的反應(yīng)系統(tǒng)之類的東西進(jìn)行額外的初始化。功能組件仍然會像傳入的新道具那樣對更改做出反應(yīng),但是在組件本身內(nèi),由于它不維護(hù)自己的狀態(tài),因此無法知道何時數(shù)據(jù)已更改。
在許多情況下,功能組件可能不合適。畢竟,使用JavaScript框架的目的是構(gòu)建更具反應(yīng)性的應(yīng)用程序。在Vue中,如果沒有適當(dāng)?shù)姆磻?yīng)系統(tǒng),則無法執(zhí)行此操作。
假設(shè)我們的組件接受一個prop.user,該對象是帶有firstName和的對象lastName,并且我們想要呈現(xiàn)一個顯示用戶全名的模板。在功能<template>組件中,我們可以通過在組件定義上提供一個方法,然后使用$optionsVue提供的屬性來訪問我們的特殊方法來做到這一點(diǎn):
<template functional> <div>{{ $options.userFullName(props.user) }}</div></template><script>export default { props: { user: Object }, userFullName(user) { return `${user.firstName} ${user.lastName}` }}</script>
子組件中處理業(yè)務(wù)
頁面中也會有很多的列表,列表中也會有各種各樣的復(fù)雜的情況,這個時候可以把一些比較繁重的業(yè)務(wù)處理存放到其子組件中。
代碼對比:
<template> <div :style="{ opacity: number / 300 }"> <div>{{ heavy() }}</div> </div></template><script>export default { props: ['number'], methods: { heavy () { const n = 100000 let result = 0 for (let i = 0; i < n; i++) { result += Math.sqrt(Math.cos(Math.sin(42))) } return result }, },}</script>
優(yōu)化后:
<template> <div :style="{ opacity: number / 300 }"> <ChildComp/> </div></template><script>export default { props: ['number'], components: { ChildComp: { methods: { heavy () { /* 長任務(wù)在子組件里。 */ } }, render (h) { return h('div', this.heavy()) } } }}</script>
當(dāng)組件隨著props:number的變化,組件patch重新渲染的時候,heavy長任務(wù)也會重新執(zhí)行。但是如果能將沒有與父組件相互依賴的元素,拆成一個組件,在父組件需要重新渲染的時候,因為與父組件沒有依賴子組件并不會跟著重新渲染,響應(yīng)的性能也能得到提升。
局部作用域
開發(fā)過程中會經(jīng)常使用到一些計算屬性或者Util函數(shù),如果我們在循環(huán)過程中,不斷的使用this.***去調(diào)用一個計算屬性的時候,每次調(diào)用這個值計算屬性都會計算一次,然而這個值卻是一個固定不變的值,就造成了很大的性能的浪費(fèi)。
如果當(dāng)我們使用這些屬性的時候,最好的方式是把對應(yīng)的值取出來,然后再去使用。
<template> <div :style="{ opacity: start / 300 }">{{ result }}</div></template><script>export default { props: ['start'], computed: { base () { return 42 }, result ({ base, start }) { let result = start for (let i = 0; i < 1000; i++) { result += Math.sqrt(Math.cos(Math.sin(base))) + base * base + base + base * 2 + base * 3 } return result }, },}</script>
總結(jié)
以上是我通過調(diào)查資料以及個人項目中的一些小經(jīng)驗得出的對于Vue性能優(yōu)化的一些方案,可能文章中一些見解存在一些問題,歡迎大家在評論區(qū)指出,大家一起學(xué)習(xí),一起進(jìn)步。