【开发者成长】Vue.js 中有哪些性能陷阱

云栖号资讯:【点击查看更多行业资讯】
在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来!

10350F14_D49D_4269_A6BE_3B3A5F23CCDB

我内心深处对游戏的热爱,让我一直渴望能自己制作一些电子游戏。几个月前我开始将这种梦想变为现实,并第一次参加了全球游戏大赛(Global Game Jam)。我和我的团队使用 Vue.js 构建了一个名为“ ZeroDaysLeft ”的游戏,其形式是 Web 端的单页面应用程序。这款游戏的主题是环境保护,我们考虑到商业活动对地球环境的影响,希望就这个话题做一些有益的探讨。使用 Vue.js 制作的游戏并不多。我的团队迟到了一天,然后用猜拳的方式选择了我们要用的框架;我们飞快地写完了代码,并在周末结束时做出了游戏的可运行版本。在本地测试时一切都很顺利。自然,我们为自己第一次写出来的游戏作品感到自豪,并希望与世界分享它。

可是问题出现了——当我们构建好应用并开始查询域时,内存占用爆表了。它几乎没法正常运行,不管换什么机器都会卡住不动,即使在强大的基于 Intel i7 处理器的系统上程序也会崩溃。游戏大赛的时间限制把我们拉回了现实,我们决定搁置生产性能问题,这样起码我们能做出一款能在自己的设备上运行的完整游戏。就像大部分的“已完成”项目一样,第二天我们就把它抛在脑后了。

但我自己没法释怀。它一直困扰着我。问题是出在 Vue.js 上吗?是 Netlify 吗?还是因为我们的取巧代码?我必须找出答案。

调查性能下降的原因

我首先使用 Lighthouse 进行了快速测试。所幸 Firefox 为此提供了一个浏览器插件。下面就是我得到的结果。

8A98CE32_DC66_48e7_A32F_1261F6945DF7

89%的数字挺不错的。实际上,与许多流行的网站相比,这个表现相当出色。这个测试指出了一些潜在问题,例如速度指数和第一次有意义且有内容的绘制步骤等。从理论上讲,解决这些问题会进一步提高分数,但不一定能解决应用面临的严重性能问题。

我们的游戏中有一些图像和音频素材资源,但是两者都不至于让游戏卡死在那里。我们也可以对这些已经优化过的资源再过度优化一遍,但这可能根本就无济于事。

这个测试无法让我们真正找出可能导致这一性能问题的原因。于是我开始想:“该不会是 Vue 的问题吧?”这种想法会冒出来也没什么理由,但要是不检查一下就是蠢了。我检查了已部署站点的控制台,结果空白一片。但警告往往不会在生产中显示。当我在本地进行相同操作时,一堆 Vue 警告让我吃了一惊。

A06374DA_4806_4363_B077_EDFFF0F940A0

像大多数开发人员一样,我对控制台警告没那么在意,觉得它们只是警告,而不代表错误;所以我一般会把注意力集中在其他地方。或许消除这些警告可以解决我的生产问题,我决定深入研究每个问题并修复它们。

所有这些警告均来自我创建的、用来显示名为 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 就可以快速将数组渲染为列表。使用它时,我们需要一个 :key 才能有效地重渲染组件。但我们将一个对象用作了一个键,这是非原始值,因此导致了这个错误。我决定将 index.description 用作一个新键,因为它是一个字符串,并且在值发生更改时可以更好地重新渲染。

> [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,因此当我们传递一个要渲染的对象时,该对象将转换为等效的字符串(即 [object Object]);并且因为这以前是我们的键,所以每个对象都将转换为 [object Object](除非对象有不同的值),进而会出现重复键警告。现在既然键不是对象,警告就会消失,效率也会提升。

> [Vue warn]: You may have an infinite update loop in a component render function.
found in
---> <Cards> at src/components/Cards.vue

就一个非常模糊的警告来说,这个警告似乎是最重要的:无限循环意味着内存消耗。这条消息并没有告诉我们可能出了什么问题,但它确实暗示了问题与组件中的 render 函数有关。也许是因为我们写的代码比较取巧,因此触发了不间断的更新,并占用了大量的计算能力,以至于使浏览器和设备崩溃。

这条警告至少告诉我们要检查 Cards.vue,所以我的第一个想法是检查组件中的反应属性,因为这可能会导致错误。反应属性在更改后会触发重新渲染。

我们正在显示 index.days 和 index.description 中的数据。但我们不会更改这些数据,我们从 cardInfo 数组获得 index。

1F3EA0D1_B09D_4c1c_8AFE_C980011CBC91

我们使用这段代码对数组中的元素进行随机排序,然后将前四个元素显示为玩家选择的选项。当用户单击一个选项时将调用 effects() 函数,它除了会计算一个动作如何影响游戏状态外,还使用 cardInfo 上的拼接原型删除前四个元素。

在 Vue 这种使用虚拟 DOM 的框架里,用上诸如 cardInfo 之类的反应属性后,每当数据属性的值更改时都会触发重新渲染。在我们的应用里,我们会直接使用 sort() 原型来更改它,然后删除元素来重新排序。所有这些都会触发“无限”的重新渲染,从而引发警告。

我决定更改数据过滤的逻辑,并停止对反应属性 cardInfo 的多次更改。我安装了 lodash.shuffle 并定义了一个计算属性 shuffledList(),它将创建一个名为 list 的 cardInfo 副本。我对其应用了随机排序操作,并返回了一个“frozen”结果,然后拆分开来显示四张卡片。我们使用了 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 在源数据数组上添加 watchers,每当发生更改时它就会触发重新渲染。这种持续的重新渲染可能会对应用程序性能产生不利影响。如果你只想可视化对象,那么 Object.freeze() 是一个很好的解决方案,可以大大提高性能。但是请务必记住,你将无法更新组件或编辑对象数据。

在这个研究过程中我还意识到,Lighthouse 可能检查的是以更直接的方式影响用户体验的应用性能指标,所以接下来我的疑问就是如何跟踪服务器上的应用程序性能。

我们是不是太依赖直觉,是不是在假设开发人员知道自己在做什么,假设他们遵循的是最佳实践?不管怎样,这次经历让我对单页应用程序的性能产生了不同的看法。大家可以在 GitHub 上查看上述项目的存储库,也欢迎大家在 Twitter 上和我打招呼。

【云栖号在线课堂】每天都有产品技术专家分享!
课程地址:https://yqh.aliyun.com/zhibo

立即加入社群,与专家面对面,及时了解课程最新动态!
【云栖号在线课堂 社群】https://c.tb.cn/F3.Z8gvnK

如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件至:yqgroup@service.aliyun.com 进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容。

原文链接
本文为云栖社区原创内容,未经允许不得转载。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/516485.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

学习笔记之数据可视化(二)—— 页面布局(下)

续上一章 2.7 地图区域(.map)2.7.1 实现步骤:2.8 用户统计模块2.8.1 布局:2.8.2 柱状图2.9 订单模块2.9.1 订单区域布局2.9.2 订单区域(order)-交互效果(此部分后续补充)3.0 销售统计( sales )3.0.1 布局3.1 渠道分布、季度进度模块3.1.1渠道分布(channel)-雷达图3.1.2…

【职业生涯】这样的开发人员每个团队都想要

云栖号资讯&#xff1a;【点击查看更多行业资讯】 在这里您可以找到不同行业的第一手的上云资讯&#xff0c;还在等什么&#xff0c;快来&#xff01; 合作是你职业生涯中不会缺少的一个部分。 什么是团队&#xff1f;团队就为了共同目标而努力的一群人。一个团队实现目标的过…

elasticsearch-7.15.2 同时支持中文ik分词器和pinyin分词器

文章目录1. 自定义分词器2. 映射模型3. 效果图1. 自定义分词器 ES如何支持拼音和中文分词 &#xff1f; 自定义分词器 支持拼音和中文分词 PUT /jd_goods {"settings": {"analysis": {"analyzer": {"ik_smart_pinyin": {"type&…

【数字康复治疗】自闭症市场能否走出供求困境

云栖号资讯&#xff1a;【点击查看更多行业资讯】 在这里您可以找到不同行业的第一手的上云资讯&#xff0c;还在等什么&#xff0c;快来&#xff01; 世界卫生组织将每年的4月2日设为“世界提高自闭症意识日”&#xff0c;旨在提高人们对自闭症和相关研究与诊断以及自闭症患者…

微软全球 AKS 女掌门人,这样击破云原生“怪圈”!

来源 | 程序人生作者 | 伍杏玲近年来&#xff0c;“云原生”成为IT界的热词&#xff0c;可什么是“云原生”&#xff1f;不少开发者表示“云里雾里”&#xff0c;更别提如何借助云原生更好地释放云价值。从云原生&#xff08;CloudNative&#xff09;一词中我们看到&#xff0c…

获取Access表字段类型的自定义函数

目录 1.函数(一)1.1 功能说明及代码1.2 自定义函数调用实例2函数(二)3 函数(三)3.1 功能说明及代码3.2 自定义函数调用4 ADO数据类型在Access、SQL Server、Oracle之间的对应关系1.函数(一) 1.1 功能说明及代码 场景:在需要对表中字段的类型进行识别判断时,当用Fie…

【数据库】一个 rm -rf 把公司整个数据库删没了

云栖号资讯&#xff1a;【点击查看更多行业资讯】 在这里您可以找到不同行业的第一手的上云资讯&#xff0c;还在等什么&#xff0c;快来&#xff01; 经历了两天不懈努力&#xff0c;终于恢复了一次误操作删除的生产服务器数据。 对本次事故过程和解决办法记录在此&#xff0c…

elasticsearch-7.15.2 集成pinyin分词器

文章目录1. 下载拼音分词器2. es集成pinyin3. 启动es4. pinyin分词5. 效果图6. 开源项目1. 下载拼音分词器 链接&#xff1a;https://github.com/medcl/elasticsearch-analysis-pinyin 2. es集成pinyin 方式任选其中一种即可 第一种&#xff1a;在线安装 ./bin/elasticsear…

【智能AI】准确率97%的开源肺炎检测模型

云栖号资讯&#xff1a;【点击查看更多行业资讯】 在这里您可以找到不同行业的第一手的上云资讯&#xff0c;还在等什么&#xff0c;快来&#xff01; 最近&#xff0c;一位澳大利亚的人工智能博士候选人在 LinkedIn 上发布了一篇关于 SARS-CoV-2 病毒的研究文章。由于极具话题…

豪气!华为放话:3年培养100万AI人才!网友神回应了

大家经常把BAT挂在嘴边&#xff0c;但是可能有些人还不知道&#xff0c;华为的体量早已超越了这三巨头&#xff0c;只是迟迟不肯上市。华为的创始人任正非曾说表&#xff1a;上不上市不重要&#xff0c;最重要的是要让中国华为的技术能够称霸全球&#xff01;华为对技术的重视&…

elasticsearch-7.15.2 配置IK中文分词器+拼音分词

文章目录1. 下载分词器2. es集成pinyin3. 启动es4. 自定义分词5. 映射模型6. 初始化数据7. 查询索引8. 效果图9. 开源项目1. 下载分词器 ik中文分词器 中文分词器&#xff1a;https://github.com/medcl/elasticsearch-analysis-ik 拼音分词器 链接&#xff1a;https://github.…

JavaScript从入门到放弃 - ES6中的对象和类

重点讲解Tab栏切换、增、删、改 1. 面向过程与面向对象2.ES6 中的对象与类2.1 对象2.2 类2.2.1 创建类2.2.1.1 语法2.2.1.2 实例2.2.2 类创建添加属性和方法2.2.3 类的继承2.2.3.1 语法2.2.3.2 实例2.2.3.3 注意事项3. 面向对象案例3.1 面向对象版tab栏切换3.1.1 案例准备3.1.1…

Gartner 容器报告:阿里云与 AWS 并列第一,领先微软、谷歌

近日&#xff0c;国际知名调研机构 Gartner 发布 2020 年容器公有云竞争格局报告&#xff0c;阿里云再度成为国内唯一入选厂商。Gartner 报告显示&#xff0c;阿里云容器服务在中国市场表现强劲&#xff0c;产品形态丰富&#xff0c;在如 Serverless 容器、服务网格、安全沙箱容…

每个程序员都必须知道的8种通用数据结构

云栖号资讯&#xff1a;【点击查看更多行业资讯】 在这里您可以找到不同行业的第一手的上云资讯&#xff0c;还在等什么&#xff0c;快来&#xff01; 数据结构是一种特殊的组织和存储数据的方式&#xff0c;可以使我们可以更高效地对存储的数据执行操作。数据结构在计算机科学…

ElasticSearch 从安装开始_01

文章目录1. windows 环境2. linux3. HEAD 插件安装4. 分布式安装5. Kibana 安装1. windows 环境 首先打开 Es 官网&#xff0c;找到 Elasticsearch&#xff1a; https://www.elastic.co/cn/downloads/elasticsearch 然后点击下载按钮&#xff0c;选择合适的版本直接下载即可。…

硅谷2020最新大数据学习路线:科学使用这一招,12周助你成为数据分析师

来源 | 智领云科技责编 | Carol数据科学到底是什么&#xff1f;数据科学是一门将数据变得有用的学科&#xff0c;它包含三个重要概念&#xff1a;统计、机器学习、数据挖掘/分析。《数据科学杂志》曾提出&#xff1a;“所谓的‘数据科学’&#xff0c;指的是那些任何与数据相关…

JavaScript从入门到放弃 - (一)构造函数和原型

目录 1. 创建对象的三种方式1.1 用字面量创建1.2 用new关键字创建1.3 借用构造函数创建2. 实例成员和静态成员2.1 实例成员2.2 静态成员3 构造函数原型4 对象原型 __ proto__5 constructor 构造函数6 构造函数、实例、原型对象三者关系7 原型链和成员的查找机制7.1 原型链7.2 查…

新基建带来新机遇!大数据产业发展需“四驱”推动

云栖号资讯&#xff1a;【点击查看更多行业资讯】 在这里您可以找到不同行业的第一手的上云资讯&#xff0c;还在等什么&#xff0c;快来&#xff01; 近段时间以来&#xff0c;“新基建”一次热度不断攀升&#xff0c;受到了科技、产业界的高度关注。实际上&#xff0c;新基建…

ElasticSearch 核心概念介绍_02

文章目录1. 集群&#xff08;Cluster&#xff09;2. 节点&#xff08;Node&#xff09;3. 索引&#xff08;Index&#xff09;4. 类型&#xff08;Type&#xff09;5. 文档&#xff08;Document&#xff09;6. 分片&#xff08;Shards&#xff09;7. 副本&#xff08;Replicas&…

JavaScript从入门到放弃 -(二)继承

目录 1. Call()2.子构造函数继承父构造函数中的属性3. 借用原型对象继承方法1. Call() 它的作用是: call()可以调用函数;call()可以修改函数运行时this的指向:使用call()的时候,参数1是修改后的this指向,参数2,参数3...使用逗号隔开连接。fun.call(thisArg,arg1,arg2,..…