笔者最近在一个Vue项目里面引入了一个动画库,但是发现性能有点异常,项目里面使用的CPU是在一个demo页面的3.5倍左右,我已经把项目里所有其它干扰的东西都给删掉了,但是CPU就是降不下去,如下图所示,正常范围是在2.1%左右波动:

但是引到项目里面就变成了7%左右波动:

这个会不会是因为html嵌套太深导致Layout等计算复杂,所以CPU上升了呢,笔者尝试把DOM结构简单化,以及加上contain: strict等Layout隔离的方法,也是没有效果。所以只能是JS执行问题了,通过Chrome devtools的Performance可以研究这个问题。

如下图所示:

上面密密麻麻的线都是requestAnimationFrame的回调,把它放大,然后查看一个回调,比较一下demo页面和Vue页面的不同之处,如下图所示:

这里明显可以看出区别,demo.html每个回调的执行时间是0.3ms左右,而Vue项目的回调执行时间达到了0.8ms左右,快接近3倍,且调用栈深了很多。多出来的这些东西是什么呢?仔细一看:

这些东西是Vue里面的,也就是Vue里面setter,部分回调里面还包含了Vue里的getter:

这个时候恍然大悟,因为Vue里面重写了变量的getter/setter,导致获取某个属性或者改写某个属性的时间变长,导致CPU上升。造成Vue重写的原因是因为在代码里面把动画库的变量当成了组件里this的属性,如下代码所示:

import Player from 'player.js';export default {data: {return {player: new Player()};}
};

然后Vue就会遍历这个player对象,给所有的属性都加上setter/getter,如下控制打印所示:

这里的Ir.set就是上面Performance里面的截图,也就是这个导致了设置Ii变量变慢了。这里我们注意到一个细节,Chrome控制台会直接打印没有覆盖setter/getter的Object,而设置了的,将会是用“(...)”代替,然后等到你去点的时候再去获取它当前的值显示出来。

从Vue源码里面可以看到,Vue会对成员变量进行defineProperty设置setter和getter:

// 代码有所删减
function defineReactive$$1 (obj, key, val) {var dep = new Dep();var property = Object.getOwnPropertyDescriptor(obj, key);// 从源码也可以看到,可以把obj的configurable置为false,Vue便不会设置getter和setterif (property && property.configurable === false) {return}// cater for pre-defined getter/settersvar getter = property && property.get;var setter = property && property.set;Object.defineProperty(obj, key, {enumerable: true,configurable: true,get: function reactiveGetter () {var value = getter ? getter.call(obj) : val;return value},set: function reactiveSetter (newVal) { var value = getter ? getter.call(obj) : val;if (setter) {setter.call(obj, newVal);} else {val = newVal;}dep.notify();}});
}

以便使用者设置值的时候做一些通知,从而达到数据驱动的目的。但同时也有可能造成性能问题,在这个例子里面是增加了0.3ms左右的调用时间。实际上这个时间几乎是可以忽略的,但是由于这个例子里面需要运行在requestAnimationFrame里面,1s调用60次,比较频繁,原本的时候也就才0.2ms,而现在由于这个setter/getter,增加了0.3ms,比正常时间多了一倍多,所以CPU就升上去了。

知道原因就能解决问题了,现在的解决方式是不要把这个player变量当成this里面的成员属性,而是把它弄到外面去,如下代码所示:

import Player from 'player.js';
let player = new Player();export default {data: {return {};}
};

(补充:从Vue的源码也可以看到,把object的configurable属性置成false也可以解决问题。)
这个时候CPU从7%降到了4%左右,快接近一半,如下图所示:

查看Performance里面的setter的调用栈就没有了,如下图所示:

但是CPU仍然是demo页面的两倍(2%和4%),这个时候继续查看调用栈,发现是一个ji的函数调用时间一个是另一个的两倍:

这两个函数点过去Source面板看代码的时候确认是两个一样的函数,这里唯一的区别可能在于demo.html用的是压缩的代码,而本地的项目是未压缩,如果打包压缩一下,放到测试环境,可以看到CPU时间基本就差不多了:

压缩代码里面会把多条语句合并为一条语句应该也会提升点性能。

综上,本文并不是说Vue的实现有问题,只是需要注意setter/getter对性能的影响,特别是在一个动画的回调里面,一般情况下对于一次性的操作影响几乎是可忽略的,应该不需要关心这个问题。另外,只是设置动画里面的setter/getter也不一定会使CPU一下子就升上去了,还要看你在setter/getter里面干了些啥,在Vue里面可以看到它的调用栈是比较深的,可能内部需要判断的东西比较多。

另外这个研究让想起了一个有趣的问题,如何让CPU使用率维持在50%?如果我写一个for写循环,那么CPU使用率一定是100%(它把一个核跑满了),如下代码所示:

let now = Date.now();
// 跑个50s
while (Date.now() - now < 50000);

这个时候CPU使用率就是100%:

如果我让它睡眠50ms,然后再干50ms,反复交替,如下代码所示:

function sleep (time) {return new Promise(resolve => {setTimeout(resolve, time);});
}
let now = Date.now();
async function start () {while (Date.now() - now < 50000) {// 睡50msawait sleep(50);let current = Date.now();// 干50mswhile (Date.now() - current < 50);}console.log('end');
}
start();

这个时候CPU使用率就会在50%左右波动,如下图所示:

是不是挺有趣的呢

baidumap vue 判断范围_一个Vue引发的性能问题相关推荐

  1. vue 画布插件_一个Vue.js插件,用于使用EaselJS控制HTML5画布

    vue 画布插件 vue-easeljs (vue-easeljs) A Vue.js plugin to control an HTML5 canvas using EaselJS. 一个Vue.j ...

  2. vue 图片引入_一个Vue的时间插件

    安装 npm install -S hzqing-vue-timeline 如何引入 main.js: // 全局注册import hzqingVueTimeline from 'hzqing-vue ...

  3. baidumap vue 判断范围_懂一点前端—Vue快速入门

    01. 什么是 Vue Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架,是当下很火的一个 JavaScript MVVM 库,是以 数据驱动和组件化 的思想构建的 ...

  4. js清空文本框的值_一个Vue.js实例控制字变大变小,含样式操作,flex布局。「603」...

    这是一个用vue.js对css操作完成的实例. 当然用了flex简单布局. 一.先创建一个html文件,记得添加vue库文件. 二.创建一盒容器vmdiv,用vue绑定它,测试vue绑定后的插入值te ...

  5. vue 同级页面调用方法_【Vue】一个vue页面调用另一个vue页面中的方法

    想仿着 vue-material 的 Demo & Document 页面的效果写一个小例子. 遇到问题的地方是: 如上图红色圈出的地方,点击 button 按钮时,无法执行 toggle() ...

  6. 5e怎么绑定一键跳投_一个 Vue 自定义指令实现一键 Copy的功能

    话不多说先看效果,这个效果是用在真实项目中的实际效果哈: 指令是啥? 按照惯例,先请出官方的解释: 指令 (Directives) 是带有 v- 前缀的特殊特性.指令特性的值预期是单个 JavaScr ...

  7. vue日期选择组件_一个Vue组件,为波斯开发人员提供日期选择器

    vue日期选择组件 Vue波斯日期选择器 (vue persian datepicker) This is a Jalali date picker component for Vue. 这是Vue的 ...

  8. vue filter对象_学习vue源码(3) 手写Vue.directive、Vue.filter、Vue.component方法

    一.Vue.directive Vue.directive(id,[definition]); 1)参数 { string } id{ Function | Object } [ definition ...

  9. axios vue 回调函数_前端Vue 面试题大全

    点蓝色字关注"程序员报刊" 「  学习 新闻 招聘 」 vue的底层原理? vue组件之间的通信? JS中判断数据类型的方法有几种? 最常见的判断方法:typeof 判断已知对象类 ...

最新文章

  1. 自动化学习的正确姿势
  2. java代码连接oracle数据库连接_在JAVA中连接Oracle数据库(例子)
  3. Windows核心编程 第七章 线程的调度、优先级和亲缘性(上)
  4. BI国产化替代进入实质阶段,新产品新方案提高加速度
  5. 【资讯】全球瞩目!无人驾驶真的来了!
  6. ASP.NET URL Routing
  7. 在 keil MDK_V5中加入arm7,arm9等一些芯片型号
  8. 40 多套 Java 完整实战项目,各个精品!
  9. cocos2dx fnt字体制作
  10. 游戏挂机时计算机设置在哪里,蜂窝助手怎么挂机 游戏蜂窝电脑版挂机设置教程...
  11. Google Chrome(谷歌浏览器)安装方法与使用技巧
  12. Python | 使用Socks5
  13. 联想摄像头无法一直运行
  14. 北京交通大学计算机仿真大作业直流调速系统仿真,计算机仿真技术大作业 12脉波整流电路仿真.doc...
  15. UE4 材质笔记之水洼(贴花)
  16. docker 容器启动成功 外部访问不到原因
  17. 《TPM原理及应用指南》学习 —— TPM历史1
  18. JQuery解决跳转无效的问题(.location.href)
  19. WPE教学之-截取操作篇
  20. 如何让无线GPS定位更准

热门文章

  1. pandas获取最大值/最小值对应的index
  2. 日志能被截取吗 log4j_Java日志体系居然这么复杂?——架构篇
  3. c语言的学生理系统,C语言学习系统的教程
  4. insert时出现主键冲突的处理方法【转载】
  5. 2091: [Poi2010]The Minima Game
  6. 如何分析一个复杂系统
  7. 终于过了。。。。。。。。。。。
  8. 计算机python指什么_python之浅谈计算机基础
  9. jq追加html属性,jQuery 操作 HTML 元素和属性的方法
  10. 基于pytorch实现图像分类——理解自动求导、计算图、静态图、动态图、pytorch入门