我心目中的游戏小子一直渴望制作电子游戏。几个月前,当我参加我的第一次全球游戏大赛时,我最近就沉迷于这种渴望。我和我的团队使用Vue.js作为单页应用程序为网络构建了一个名为“ ZeroDaysLeft ” 的游戏。该游戏具有绿色主题,我们考虑了资本主义对地球的环境影响,并希望对此进行有益的探讨。使用Vue.js制作的游戏并不多。我的团队迟到了一天,在用剪刀石头般的文字游戏挑选了我们的框架之后,我们急于对其进行编码,并在周末结束时使我们的游戏开始工作。在本地,一切工作都非常好。自然,我们为自己的代码《弗兰肯斯坦》感到自豪,并希望与世界分享。
仅有一个问题-当我们构建应用程序并查询域时,这真是一场记忆大战。它几乎无法正常工作,我们尝试在其上运行的每台计算机都将挂起处理地狱,即使我强大的基于Intel i7处理器的系统也会崩溃。游戏拥堵的时间限制使我们回到了现实,我们决定搁置生产性能问题,以便至少可以在设备上投放完整的游戏。就像几乎每个“已完成”的项目一样,第二天我们就忘记了它。
除了我不能放弃。它一直困扰着我。是Vue.js吗?是Netlify吗?这是我们的代码吗?我必须找出答案。
我首先使用Lighthouse进行了快速测试。幸运的是,Firefox 为此提供了一个浏览器插件。这就是我回来的。
89%不错。实际上,与许多广泛使用的网站相比,它是不错的。该测试提到了潜在的问题,例如速度指数和第一个有意义且有意义的涂料。从理论上讲,解决这些问题会使分数更高,但不一定会改善应用程序的巨大性能问题。我们有一些图像和音频资产,尽管两者都不足以引起挂起。我们可以对这些已经优化的资产进行过度优化,但这可能根本无济于事。
该测试并没有为我们提供任何可能导致此性能问题的真正见解。此时,我在想“是Vue吗?” 我没有理由这样想,但是不检查就太愚蠢了。我检查控制台中已部署的站点,该站点为空白。警告通常不会在生产中显示。当我在本地执行相同操作时,我受到一些Vue警告的打击。
像大多数开发人员一样,我对控制台警告的看法是警告只是警告而不是错误,因此我的注意力更好地集中在其他方面。我寄希望于消除这些警告可以解决我的生产问题。我决定深入研究每个问题并进行修复。
所有这些警告都来自我创建的用于显示名为的选项的Cards.vue
组件,因此该组件可能需要大量重写。
我决定按顺序解决这些控制台警告。
> [Vue警告]:避免将非原始值用作键,而应使用字符串/数字值。 在发现 --->在src / components / Cards.vue
Vue.js有很多指令,使使用框架更加直观,例如v-for
,可以快速将数组呈现为列表。当我们使用它时,我们需要具有一个:key
使组件有效重新渲染的功能。但是,我们将对象用作键,这是非原始值,因此导致此错误。我决定使用index.description
as作为新键,因为它是一个字符串,并且只要值发生更改,就会使重新渲染更加有效。
> [Vue警告]:检测到重复的密钥:“ [object Object]”。这可能会导致更新错误。
在发现
---> <卡>在SRC /组件/ Cards.vue
更改:key
为与字符串index.description
-因为先前的错误修复了这个重复键错误。我们只能将字符串类型写入DOM,因此,当我们传递要渲染的对象时,该对象将转换为等效的字符串(即[object Object]),并且因为这以前是我们的键,所以每个对象都拥有不同的值,将转换为[object Object],因此出现重复的键警告。既然键不是对象,警告就会消失。所以要提高效率。
> [Vue警告]:组件渲染功能中可能存在无限的更新循环。在发现---> 在src / components / Cards.vue
对于一个非常模糊的警告,此警告似乎是最重要的。无限循环是内存消耗的代名词。该消息并未告诉我们可能出了什么问题。它确实暗示它与组件中的render函数有关。也许是因为我们的骇客代码,我们触发了不间断的更新,这占用了大量的计算能力,以至于使浏览器和设备崩溃。
警告至少告诉我们要检查Cards.vue
,所以我的第一个想法是检查组件中的反应性,因为这可能会导致错误。反应性属性在更改后会触发重新渲染。
我们正在显示index.days
和中的数据index.description
。但是,我们不会更改此数据。我们index
从cardInfo
数组派生。
> V-用于 = “在cardInfo索引的.sort(()=>数学。随机() - 0.7).slice(0,4)”
我们使用此代码块对数组中的元素进行随机排序,然后将前四个元素显示为玩家选择的选项。当用户单击一个选项时,该effects()
函数将被调用,除了计算动作如何影响游戏状态外,它还会使用拼接原型cardInfo
删除前四个元素。
像cardInfo
在使用虚拟DOM的Vue这样的框架中使用响应式属性一样,只要数据属性的值发生更改,就会触发重新渲染。在我们的案例中,我们将直接使用sort()
原型对其进行更改,然后删除元素以仅对其进行排序。所有这些都会触发“无限”重新渲染,从而引发警告。
我决定更改数据过滤方式的逻辑,并停止对反应性进行多次更改cardInfo
。我安装lodash.shuffle
,并定义了计算性能,shuffledList()
,这将创建的副本cardInfo
叫list
。我对其应用了随机播放操作,并返回了“冻结”结果,该结果将被切片以显示四张卡片。我们用了Object.freeze()
这将使我们返回的对象不可变,从而完全停止所有重新渲染。问题解决了。
老实说,当我开始调查时,我认为我必须优化很多资产。它只是说明了在使用许多框架抽象时我们必须非常小心—特别是在Vue中,必须正确且仅在必要时才使用每个指令,因为它们绝对有折衷。
这让我想到了我在做什么,这可能会给我的应用程序增加不必要的性能问题。大多数现代的前端框架都进行了很多抽象,使我们更容易地为Web制作应用程序,重要的是要记住在使用事物时可能出现的潜在性能问题。我经常使用Vue.js,并决定探索一些我使用的指令,甚至不考虑它们可能对我的应用程序带来的性能影响。特别是三个非常流行的指令对我来说很突出。
v-if
和 v-show
这两个指令都用于有条件地渲染元素,但是它们在幕后的工作方式却大不相同,因此,因此必须使用不同的方式。v-if
最初不渲染组件,仅在条件为真时才渲染组件。这意味着,如果您多次切换组件的可见性,则会重复重新渲染它。如果要多次更改组件的可见性,则不想使用此功能。这会影响您的表现。
一个很好的选择是v-show
。无论使用CSS如何,这都会呈现您的组件,但是只会根据条件是true还是false使其可见。这种方法确实有其缺点,因为它不会将非必要组件的渲染推迟到实际需要它们出现在屏幕上的时候。如果您的初始渲染不很重,则效果很好。
v-for
此伪指令通常用于从数组中呈现列表。它具有形式的特殊语法item in list
,其中list
是源数据数组,而item是要对其进行迭代的数组元素的别名。默认情况下,Vue在源数据阵列上添加监视程序,每当发生更改时,该监视程序就会触发重新渲染。这种持续的重新渲染可能会对应用程序性能产生不利影响。考虑实用程序很重要,如果您只想可视化对象,那么这Object.freeze()
是一个很好的解决方案,可以大大提高性能。但是请务必记住,您将无法更新组件或编辑对象数据,这一点很重要。
这样做并意识到Lighthouse可能会检查以更直接的方式查看可能影响用户体验的应用程序性能,我被问到如何跟踪服务器上的应用程序性能。我们是否让直觉和开发人员知道自己在做什么以及正在使用最佳实践的假设?无论如何,这种整体经验使我对单页应用程序性能有不同的看法。随时在GitHub上查看项目存储库,或在Twitter上对我问好。