發(fā)布于:2020-12-24 16:16:25
0
138
0
作為一個游戲玩家,我的內(nèi)心一直有一種做電子游戲的強烈欲望。幾個月前,當我第一次參加Global Game Jam時,我就沉迷于這種沖動。我和我的團隊使用Vue.js為web創(chuàng)建了一個名為“ZeroDaysLeft”的單頁應用程序。這款游戲的主題是綠色,我們考慮了資本主義對地球環(huán)境的影響,并想在游戲中添加一些有益的信息。使用vuv .js制作的游戲并不多。我的團隊晚了一天,在玩了一場石頭剪刀布的游戲來選擇我們的框架后,我們趕緊去編碼它,并在周末結(jié)束時讓我們的游戲運行起來。從本地來看,一切都很順利。自然,我們?yōu)槲覀兊拇a弗蘭肯斯坦感到自豪,并想與世界分享它。
只有一個問題,當我們構(gòu)建應用程序和查詢域時,它是如此占用內(nèi)存。它幾乎不能工作,我們試圖運行它的每臺機器都會在處理地獄中掛起——甚至我那健壯的基于Intel i7處理器的系統(tǒng)也會崩潰。game jam的時間限制將我們帶回到現(xiàn)實中,我們決定將生產(chǎn)性能問題放在一邊,這樣我們至少可以在我們的設(shè)備上推出一款完整的游戲。就像幾乎每一個“完成”的項目一樣,我們第二天就忘記了。
只是我無法釋懷。它一直困擾著我。Vue.js嗎?Netlify嗎?是我們的密碼嗎?我必須弄清楚。
調(diào)查經(jīng)濟放緩
我用Lighthouse做了一個快速的測試。幸運的是,F(xiàn)irefox有一個瀏覽器插件。這就是我得到的。
89%不壞。事實上,與許多廣泛使用的網(wǎng)站相比,它是體面的。測試提到了一些潛在的問題,如速度索引和第一個內(nèi)容和有意義的油漆。從理論上講,解決這些問題可以提高分數(shù),但不一定能改善應用程序巨大的性能問題。我們有兩個圖像和音頻資產(chǎn),但都不夠大,不會導致掛起。我們可以過度優(yōu)化這些已經(jīng)優(yōu)化過的資產(chǎn),但這可能對我們沒有任何幫助。
測試并沒有為我們提供任何可能導致這種性能問題的真正見解。這時,我在想“是Vue嗎?”“我沒有理由這么想,但如果我不去核實,那就太愚蠢了。我檢查控制臺部署的站點,它是空白的。警告通常不會在生產(chǎn)環(huán)境中顯示。當我在本地做同樣的操作時,我被幾個Vue警告擊中了頭部。
與大多數(shù)開發(fā)人員一樣,我對控制臺警告的理解是,它們只是警告而不是錯誤,因此我的注意力更好地集中在其他事情上。我一直希望消除這些警告可以修復我的生產(chǎn)問題。我決定再深入一點,然后修復它們。
所有這些警告都來自我創(chuàng)建的用于顯示名為Cards的選項的組件。vue,因此該組件可能需要大量重寫。
我決定按順序處理這些控制臺警告。
> [Vue warn]: Avoid using non-primitive value as key, use string/number value instead.
found in
---> <Cards> at src/components/Cards.vue
Vue.js有很多指令,使使用框架更加直觀,例如v-for,它可以快速將數(shù)組呈現(xiàn)為列表。 使用它時,我們需要一個:key才能有效地重新渲染組件。 但是,我們使用對象作為鍵,這是非原始值,因此導致此錯誤。 我決定將index.description用作新鍵,因為它是一個字符串,并且只要值發(fā)生更改,就可以更有效地重新呈現(xiàn)。
> [Vue warn]: Duplicate keys detected: '[object Object]'. This may cause an update error.
found in
---> <Cards> at src/components/Cards.vue
將:key更改為字符串(index.description),以解決上一個錯誤,從而解決了重復的鍵錯誤。 我們只能將字符串類型寫入DOM,因此,當我們傳遞要渲染的對象時,該對象將轉(zhuǎn)換為等效的字符串(即[object Object]),并且因為這以前是我們的鍵,所以每個對象盡管擁有不同的值 ,將轉(zhuǎn)換為[object Object],因此出現(xiàn)重復的鍵警告。 既然鑰匙不是物體,警告就會消失。 所以要提高效率。
> [Vue warn]: You may have an infinite update loop in a component render function.
found in
---> <Cards> at src/components/Cards.vue
對于一個非常模糊的警告,此警告似乎是最重要的。 無限循環(huán)是內(nèi)存消耗的代名詞。 該消息并未告訴我們可能出了什么問題。 它確實暗示它與組件中的render函數(shù)有關(guān)。 也許是因為我們的駭客代碼,我們觸發(fā)了不間斷的更新,而這占用了太多的計算能力,從而導致瀏覽器和設(shè)備崩潰。
該警告至少告訴我們要檢查Cards.vue,所以我的第一個想法是檢查組件中的反應性,因為這可能會導致錯誤。 反應性屬性在更改后會觸發(fā)重新渲染。
我們正在顯示index.days和index.description中的數(shù)據(jù)。 但是,我們不會更改此數(shù)據(jù)。 我們從cardInfo數(shù)組獲得索引。
> v-for="index in cardInfo.sort(() => Math.random() - 0.7).slice(0,4)"
我們使用此代碼塊對數(shù)組中的元素進行隨機排序,然后將前四個元素顯示為玩家選擇的選項。當用戶單擊一個選項時,將調(diào)用effects()函數(shù),除了計算動作如何影響游戲狀態(tài)之外,它還使用cardInfo上的拼接原型刪除前四個元素。
在使用虛擬DOM的Vue這樣的框架中,隨著諸如cardInfo之類的反應性屬性一起使用,每當數(shù)據(jù)屬性的值更改時,都會觸發(fā)重新渲染。在本例中,我們將直接使用sort()原型對其進行更改,然后刪除元素以僅對其進行重新排序。所有這些都會觸發(fā)“無限”重新渲染,從而引發(fā)警告。
我決定更改如何過濾數(shù)據(jù)的邏輯,并停止對反應性屬性cardInfo進行多次更改。我安裝了lodash.shuffle并定義了一個計算屬性shuffledList(),它將創(chuàng)建一個名為list的cardInfo副本。我對其應用了隨機播放操作,并返回了“凍結(jié)”結(jié)果,該結(jié)果將被切片以顯示四張卡片。我們使用了Object.freeze(),它將使我們返回的對象不可變,從而完全停止了所有重新渲染。問題解決了。
被我的框架絆倒
老實說,當我開始調(diào)查時,我認為我必須優(yōu)化很多資產(chǎn)。 它只是說明了在使用許多框架抽象時我們必須非常小心—特別是在Vue中,必須正確且僅在必要時才使用每個指令,因為它們絕對有折衷。
這讓我想到了我在做什么,這可能會給我的應用程序增加不必要的性能問題。 大多數(shù)現(xiàn)代的前端框架都進行了很多抽象,使我們更容易地為Web制作應用程序。記住使用這些東西可能會引起的潛在性能問題很重要。 我經(jīng)常使用Vue.js,并決定探索一些我使用的指令,甚至不考慮它們可能對我的應用程序帶來的性能影響。 特別是三個非常流行的指令對我來說很突出。
v-if
and v-show
這兩個指令都用于有條件地渲染元素,但是它們在幕后的工作方式卻大不相同,因此,因此必須使用不同的方式。 v-if最初不渲染組件,僅在條件為真時才渲染組件。 這意味著,如果您多次切換組件的可見性,它將被重復重新渲染。 如果您要多次更改組件的可見性,則不想使用此功能。 這會影響您的表現(xiàn)。
v-show是一個很好的選擇。 無論使用CSS如何,這都會呈現(xiàn)您的組件,但是只會根據(jù)條件是true還是false使其可見。 這種方法確實有其缺點,因為它不會將非必要組件的渲染推遲到實際需要它們出現(xiàn)在屏幕上的時候。 如果您的初始渲染不太沉重,則效果很好。
v-for
此偽指令通常用于從數(shù)組中呈現(xiàn)列表。它具有item in list形式的特殊語法,其中l(wèi)ist是源數(shù)據(jù)數(shù)組,而item是要迭代的數(shù)組元素的別名。默認情況下,Vue在源數(shù)據(jù)陣列上添加監(jiān)視程序,每當發(fā)生更改時,該監(jiān)視程序就會觸發(fā)重新渲染。持續(xù)不斷的重新渲染會對應用程序性能產(chǎn)生不利影響??紤]實用程序很重要,如果您只想可視化對象,則Object.freeze()是一個很好的解決方案,可以大大提高性能。但是請務必記住,您將無法更新組件或編輯對象數(shù)據(jù)。
這樣做并意識到Lighthouse可能會檢查以更直接的方式查看可能影響用戶體驗的應用程序性能,我被問到如何跟蹤服務器上的應用程序性能。我們是否讓直覺和開發(fā)人員知道自己在做什么以及正在使用最佳實踐的假設(shè)?無論如何,這種整體經(jīng)驗使我對單頁應用程序性能有不同的看法。隨時在GitHub上查看項目存儲庫,或在Twitter上對我問好。