壹 ❀ 引

公司产品一直在做企业项目研发工具,所以我们自己当然也会用自己的产品去管理公司大小项目,但在此之前,项目管理体验上一直存在一个卡顿问题。比如我刚登录上账号,在项目里随便到处点点到处跳转页面,然后点击项目头部的搜索功能进行任意搜索,并成功跳转到搜索结果页后,再点击chrome的回退按钮回到上个页面,就会遇到长达10S的页面卡顿,我的电脑是16G M1芯片都要卡这么久,像测试同学配置相对差一点的MAC,chrome甚至会卡到直接失去响应,总而言之,如果客户碰巧也这么操作了,使用体验自然非常很好。

贰 ❀ Performance性能分析

好在chrome已经提供了Performance帮助我们分析页面加载性能瓶颈问题。F12打开控制台,点击Performance按钮就能看到如下界面,考虑到我的电脑配置较好,为了模拟低配置,更好的复现问题,所以我将CPU选项选择为降低6倍性能6x slowdown,另外,上面还有个Network用于降网速,这个可用来模拟网络慢的情况,因为我这问题跟网络没啥关系,这里就不管了。

然后我还是按照上面说的操作,在项目里乱点一通,到处跳转,之后搜索,进入搜索页面,这时候就可以开启Performance的录制功能,也就是上图那个黑色的圆形按钮,然后点击chrome的回退按钮,卡顿几十秒后页面终于恢复正常,我们再点击录制按钮结束录制,少许片刻,于是我们得到了如下信息:

让我们把目光看向CPU的火焰图,从5000ms到60000ms这么长长的一段,接近55秒的时间内CPU使用都占了一半(黄色区域),那么性能问题自然出现在这55s之间。直接看一眼下面的统计报表,也能发现总共1.1min中,有62446ms在执行JS,而等待,渲染,重绘都在百ms,因此跟这些没太大关系。

我们拖拽鼠标,将分析范围选中为有问题的55S之间,可以看到是一个Task任务总共耗时是54秒,注意,这是一个长任务,也就是单一跑完这个任务就用了这么久。顺带解释下这段黄绿蓝区域的含义,横向表示这个任务耗时的长度,长度越长说明用时越久,纵向表示这个任务的调用栈,比如总任务名为Task,task下又分别包含了哪些任务呢?于是就有了纵向这样一列。

由于任务过长,我们不得不继续滚动鼠标,将选中范围精确到更小的执行粒子上,神奇的事情发生了,随着我选中范围越来越小,下面的调用栈名称居然就没变过,也就是说这么长的时间里,执行的JS过程就是如下这么一段,我们前面说了,纵向表示调用栈,而在最下的anonymous下,存在无数个黄色的小段落,粗略来看,这个方法估计被执行了上千或者上万遍。

既然问题出在这,我们通过鼠标选中这个匿名函数,在Sunmary表报处我们就能看到这个函数所在的文件了,一个名为selector.js的文件,点击进入,成功找到了可能有问题的代码:

看样子写这块代码的同学估计也猜到这里特别耗性能,所以才使用了memoize做了缓存,只是没想到第一次缓存准备数据还是要等待几十秒。出于好奇,我在这段代码前后加了console.timeconsole.timeEnd,刷新,重新走一遍复现流程,看了眼控制台,人傻了...接近46秒,好奇看了眼这里的permissionRuleListMap,居然有十几万的数据。

叁 ❀ 优化思路

怎么优化呢?其实文章标题已经给了答案了,就是一个小小的concat引发的问题,这段代码第一获取了名为permissionRuleListMap的所有key,然后遍历key,依次去取key对应的内容,再利用concat将内容加入到新数组resultList取,事实上这里都不需要做Object.keys这部操作,毕竟Object.keys也是一次遍历,十几万的数据跑一遍也需要时间,我们完完全全可以一遍遍历搞定,改为如下代码:

const resultList = [];
// 一次遍历,不用单独获取key
for (const key in permissionRuleListMap) {
// 用push取代concat
resultList.push(...permissionRuleListMap[key]);
}
return resultList;

重走上述流程,然后继续点回退,神奇的事情发生啦,看一眼控制台时间输出,现在只要几百毫秒了。

肆 ❀ 谨慎使用concat

为了更好的验证这两个方法的快慢,我们可以控制变量,声明一个包含10W个[1,2]的数组,并将其复制到一个新数组中去,让我们来对比时间:

const arr = new Array(100000).fill([1, 2]);
let a1 = [];
let a2 = [];
// 使用concat
console.time('1');
for (let i = 0; i < arr.length; i++) {
a1 = a1.concat(arr[i]);
};
console.timeEnd('1');
// 使用push
console.time('2');
for (let i = 0; i < arr.length; i++) {
a2.push(...arr[i]);
}
console.timeEnd('2');

我们都知道,concat是返回一个新数组,所以每次遍历,JS都需要新开一个内存,创建一个新数组,用于保存合并后的数组内容,所以遍历10W次,那么就需要重复开10W个内存,再将数组元素依次放进去,只要数组够大,它的时间只会要的更久。

相对而言push就简单了,即便执行10W次,我们操作的始终是一个数组,每次我们都只是在这个数组上新加几个空位,用于依次存放新的数组元素而已,脑补一下这个过程,性能谁更优一目了然。

Javascript Array.push is 945x faster than Array.concat一文中,也有阐述为啥pushconcat快了接近945倍,这里我们只需要得知这个结论就好,总而言之,请谨慎使用concat方法,如果你的数据量较大,就一定得留意这一点,那么本文就记录到这里啦。

push竟比concat快上数百倍?记一个concat在十万级数据引发的性能问题的更多相关文章

  1. 写markdown博客如何截图并快速上传到图床——记一个工具插件的实现

    1. 背景 写博客有一个自己的图床是不错的选择,如果不借助工具,在markdown博客中添加图片的步骤如下: 截取图片,保存到本地(得来回点对话框,选择保存路径,选择文件类型,输入文件名). 上传到图 ...

  2. 写markdown博客如何将截图快速上传到图床——记一个工具插件的实现(windows版 开源)

    打造一个上传图片到图床利器的插件(Mac版 开源)(2018-06-24 19:44) 更新于2018年2月 做了以下改动: 1.修复了一个bug,把服务器区域做成可配: 七牛有华北,华东,华南以及美 ...

  3. 数百个 HTML5 例子学习 HT 图形组件 – 3D建模篇

    http://www.hightopo.com/demo/pipeline/index.html <数百个 HTML5 例子学习 HT 图形组件 – WebGL 3D 篇>里提到 HT 很 ...

  4. 数百个 HTML5 例子学习 HT 图形组件 – 3D 建模篇

    http://www.hightopo.com/demo/pipeline/index.html <数百个 HTML5 例子学习 HT 图形组件 – WebGL 3D 篇>里提到 HT 很 ...

  5. 分享数百个 HT 工业互联网 2D 3D 可视化应用案例

    过去的 2018 年,我们认为是国内工业互联网可视化的元年,图扑软件作为在工业可视化领域的重度参与者,一线见证了众多 HTML5/Web 化.2D/3D 化的项目在工业界应用落地,我们觉得有必要在此分 ...

  6. 近万字案例:Rancher + VMware PKS实现全球数百站点K8S集群管理

    Sovereign Systems是一家成立于2007年的技术咨询公司,帮助客户将传统数据中心技术和应用程序转换为更高效的.基于云的技术平台,以更好地应对业务挑战.曾连续3年提名CRN,并且在2012 ...

  7. 数百个 HTML5 例子学习 HT 图形组件 – 拓扑图篇

    HT 是啥:Everything you need to create cutting-edge 2D and 3D visualization. 这口号是当年心目中的产品方向,接着就朝这个方向慢慢打 ...

  8. 微软正式发布VS2015和.Net为开发者提供数百个新功能

    今天,我很高兴地向大家宣布:Visual Studio 2015 和 .Net 4.6 的正式版本现已提供下载! 自去年十一月我们提出了微软开发技术的愿景:让所有开发者,无论他在什么平台,开发哪种应用 ...

  9. 分享数百个 HT 工业互联网 2D 3D 可视化应用案例之 2019 篇

    继<分享数百个 HT 工业互联网 2D 3D 可视化应用案例>2018 篇,图扑软件定义 2018 为国内工业互联网可视化的元年后,2019 年里我们与各行业客户进行了更深度合作,拓展了H ...

  10. 数百个 HT 工业互联网 2D 3D 可视化应用案例分享 - 2019 篇

    继<分享数百个 HT 工业互联网 2D 3D 可视化应用案例>2018 篇,图扑软件定义 2018 为国内工业互联网可视化的元年后,2019 年里我们与各行业客户进行了更深度合作,拓展了H ...

随机推荐

  1. Linux telnet安装及端口测试联通性

    安装步骤: 可使用该文中的步骤进行安装,已经过本人验证,是可以安装成功的: https://blog.csdn.net/doubleqinyan/article/details/80492421 安装 ...

  2. 2023年度总结,互联网寒冬是躺平OR寻找风口

    一.前言 又到了年底,这一年过的真的好快,犹如白驹过隙. 身体快跃过去了,灵魂还没有. 拿起键盘却迟迟无法下手,经过三天终于完成了! 这是很颓很丧的一年,很难看到自己的成长,就像登山卡在半山腰,开车堵 ...

  3. 【C/C++】sscanf函数和正则表达式

    此文所有的实验都是基于下面的程序:char str[10];for (int i = 0; i < 10; i++) str[i] = '!';执行完后str的值为str = "!!! ...

  4. Linux-目录-cd-mdkir-rm-ls-pwd

  5. [转帖]《Linux性能优化实战》笔记(20)—— 使用 tcpdump 和 Wireshark 分析网络流量

    tcpdump 和 Wireshark 是最常用的网络抓包和分析工具,更是分析网络性能必不可少的利器. tcpdump 仅支持命令行格式使用,常用在服务器中抓取和分析网络包.Wireshark 除了可 ...

  6. [转帖]煮饺子与 docker、kubernetes 之间的关系

      前言:云原生的概念最近非常火爆,企业落地云原生的愿望也越发强烈.看过很多关于云原生的文章,要么云山雾罩,要么曲高和寡. 所以笔者就有了写<大话云原生>系列文章的想法,期望用最通俗.简单 ...

  7. 【转贴】linux命令总结之seq命令

    linux命令总结之seq命令 https://www.cnblogs.com/ginvip/p/6351720.html 功能: seq命令用于产生从某个数到另外一个数之间的所有整数. 语法: 1 ...

  8. qperf 简要总结 - 延迟与带宽信息

    总结 同一个虚拟机: 延迟: 12us 带宽: 6GB/S 同一个物理机上面的虚拟机: 延迟: 50us-100us 带宽: 1.2GB/S 同一个交换机上面的虚拟机: 延迟: 60us 带宽: 12 ...

  9. 2024了,我不想再用AOP收集业务操作日志了 | 京东云技术团队

    0.背景 在近期的项目中,系统涉及到针对系统的业务操作日志统计功能,由于本系统位于业务链路的中心环节,负责接收上游系统的数据,并将基于用户操作产生的数据传递至下游系统,鉴于业务链路的复杂性和操作场景的 ...

  10. 小Min_25筛小记🐤

    这里的小Min_25筛,可以筛出 $10^11$ 以内所有质数的完全积性函数之和 注意事项: 1. cmd 的题解里面下标写得不清楚,应该是 $S'(p_k-1,k-1)$ 而不是 $S'(p_{k- ...