未加星标

利用 JavaScript Profiler 分析 Vue 性能问题

字体大小 | |
[前端(javascript) 所属分类 前端(javascript) | 发布者 店小二05 | 时间 2019 | 作者 红领巾 ] 0人收藏点击收藏

在实现 InputNumber 组件的时候,有一个功能是按住 + 或 - 按钮时,组件的值在不断的自增或者自减,具体如下图


利用 JavaScript Profiler 分析 Vue 性能问题

当组件的值自增到一定数量之后,组件会开始卡顿,并且页面上下滚动也会有明显的延迟。

问题体验

相关代码

2. 定位问题 <script> export default { name: "input-number", ... methods: { handleClick(type) { const { step } = this; const period = 10; const timerHandle = () => { const { addDisabled, decDisabled } = this; if (!addDisabled && type === "add") this.inputNumberValue += step; if (!decDisabled && type === "dec") this.inputNumberValue -= step; }; const timer = setInterval(timerHandle, period); const startTime = new Date(); const handler = () => { const endTime = new Date(); if (endTime - startTime < period) timerHandle(); clearInterval(timer); document.removeEventListener("mouseup", handler, false); }; document.addEventListener("mouseup", handler, false); } ... }; </script> 复制代码

首先定位问题发生的位置,直观上感受应该是点击之后不无端自增发生的卡顿,对应代码中的 handleClick 函数,它将 click 事件分为 mousedown 以及 mouseup ,当触发 mousedown 事件时候,调用一个 setInterval 定时执行组件值变化的函数。

初步定位问题应该就发生在 timerHandle 之后,当 inputNumberValue 发生变化之后,它会按照一定的规则来改变 inputValue 的值,从而触发 $emit(input, this.inputValue) 来完成 v-model 。

computed: { inputNumberValue: { get() { return this.inputValue; }, set(value) { // ...一定规则 this.inputValue = limits.find(limit => limit.need(value)).value; } } }, watch: { value: { handler(newVal) { console.timeEnd() this.inputNumberValue = newVal; }, immediate: true }, inputValue(newVal) { this.$emit("input", newVal); } } 复制代码

利用 console.time 以及 console.timeEnd 来排查,那一步发生的卡顿,检测整个 v-model 变化的流程。

也就是在 timerHandle 以及 watch value handler 内添加 console.time 以及 console.timeEnd ,具体如下

const timerHandle = () => { const { addDisabled, decDisabled } = this; if (!addDisabled && type === "add") this.inputNumberValue += step; if (!decDisabled && type === "dec") this.inputNumberValue -= step; console.time(); }; watch: { value: { handler(newVal) { console.timeEnd() this.inputNumberValue = newVal; }, immediate: true } } 复制代码

然后运行,发现运行时间是在不断地增加的,这时候问题的可以归类为,inputNumber 组件的值在不断地变动,导致的 update 的时间会不断地增长。


利用 JavaScript Profiler 分析 Vue 性能问题

接下来要判断具体是哪一句js导致整个页面的 update 时间不断地变长,利用 Chrome 的 javascript Profiler 来完成该工作。打开开发者工具


利用 JavaScript Profiler 分析 Vue 性能问题

利用这个面板你可以追踪网页程序的内存泄漏问题,进一步提升程序的JavaScript执行性能,点击Start 按钮,然后去复现刚才的操作,得到结果如下


利用 JavaScript Profiler 分析 Vue 性能问题

图中标识处有三个模式:

Chart 按时间先后顺序显示的火焰图; Heavy(Bottom Up) 根据对性能的消耗影响列出所有的函数,并可以查看该函数的调用路径; Tree(Top Down) 从调用栈的顶端(最初调用的位置)开始,显示调用结构的总体的树状图情况。

选择 Tree(Top Down) 模式,得到结果如下


利用 JavaScript Profiler 分析 Vue 性能问题

可以看出 flushCallbacksvue 函数占用了74.66%的 Total Time,所以需要对它进行分析


利用 JavaScript Profiler 分析 Vue 性能问题

在它的调用栈中,关键的一步是 Vue._update ,它的主要功能是将 Vnode 渲染成真实DOM,所以上述的卡顿问题果然出现在渲染这一步。

继续分析,发现主要问题在与 updateDirctives 这个函数内,看来问题和指令的更新相关。

最后,发现原来是 highlightBlock 的锅,因为要完成页面中代码高亮的需求,开发了一个指令

import hljs from 'highlight.js/lib/highlight'; Vue.directive ('highlight', function (el) { let blocks = el.querySelectorAll ('code'); Array.prototype.forEach.call (blocks, block => { hljs.highlightBlock (block); }); }); 复制代码

当 InputNumber 组件 v-model 所绑定的父组件 data 变动时候,会导致 v-highlight 指令不断地更新,使得页面卡顿。

3. 解决问题

只需要将该指令的高亮代码的函数写在 bind 里面,这样就只调用一次,指令第一次绑定到元素时调用。

Vue.directive ('highlight', { bind (el) { let blocks = el.querySelectorAll ('code'); Array.prototype.forEach.call (blocks, block => { hljs.highlightBlock (block); }); } }); 复制代码

原创声明: 该文章为原创文章,转载请注明出处。

本文前端(javascript)相关术语:javascript是什么意思 javascript下载 javascript权威指南 javascript基础教程 javascript 正则表达式 javascript设计模式 javascript高级程序设计 精通javascript javascript教程

分页:12
转载请注明
本文标题:利用 JavaScript Profiler 分析 Vue 性能问题
本站链接:https://www.codesec.net/view/628532.html


1.凡CodeSecTeam转载的文章,均出自其它媒体或其他官网介绍,目的在于传递更多的信息,并不代表本站赞同其观点和其真实性负责;
2.转载的文章仅代表原创作者观点,与本站无关。其原创性以及文中陈述文字和内容未经本站证实,本站对该文以及其中全部或者部分内容、文字的真实性、完整性、及时性,不作出任何保证或承若;
3.如本站转载稿涉及版权等问题,请作者及时联系本站,我们会及时处理。
登录后可拥有收藏文章、关注作者等权限...
技术大类 技术大类 | 前端(javascript) | 评论(0) | 阅读(42)