出人意料的性能测试

发表于:2019-3-05 14:35

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:Dcison    来源:掘金

  前言
  在开发公司一次需求(就是一个3层或者4层嵌套的表单数据(都展示层输入框))的各种处理时,脑子灵光一闪,想到了一些提高性能的方案,但是苦于时间(其实是自己拖延),一直没有实际测试性能是否真的有提高。直到这几天才真正的去测试了一下,结果得出的结论出乎我的意料。
  表单的数据结构
  测试嘛,数据肯定不能用公司的,但是要接近公司的真实数据量,二话不多上,直接上 Mock.js ,配置如下:
  {
  "data|4": [{
  "title": "@ctitle(5)",
  "content|25": [{
  "title": "@ctitle(5)",
  "content|25": [{
  "key": "@string(6)",
  "title": "@ctitle(5)",
  "value": "@word(3)"
  }]
  }]
  }]
  }
  上面配置只是简版的,实际开发中的数据还有很多其他信息,但是不影响我的测试。
  测试代码
  看到数据结构可能很多老哥都猜到我要测啥了,我们在每次修改输入值的时候都要遍历数据,我们测的就是每次修改导致遍历数组所需要的时间。首先展示的代码如下:
   renderForm(data) {
  return <>
  {
  data.map((item, index) => {
  return <div  className="yijimokuai">
  <h1>{item.title}</h1>
  {
  item.content.map((_item, _index) => {
  return <div  className="erjimokuai">
  <h2>{_item.title}</h2>
  {
  _item.content.map((__item,__index) => {
  return <div >
  <span>{__item.title}:</span>
  {/* <input type="text" value={__item.value} onChange={(e) => this.handleChange1(e,__item.key)}/> */}
  {/* <input type="text" value={__item.value} onChange={(e) => this.handleChange2(e,__item.key)}/> */}
  {/* <input type="text" value={__item.value} onChange={(e) => this.handleChange3(e,[index,_index,__index])}/> */}
  <input type="text" value={this.state.dict[__item.key]} onChange={(e) => this.handleChange4(e,__item.key)}/>
  </div>
  })
  }
  </div>
  })
  }
  </div>
  })
  }
  </>
  }
  有4种input,每种对应一个不同的Onchange方案:
  方案1:没有优化
    handleChange1(e,key){
  console.time('test1');
  let data = this.state.data;
  for (let i = 0,flen = data.length; i < flen ;i++) {
  for (let j = 0,slen = data[i].content.length; j< slen; j++) {
  for (let k = 0,klen = data[i].content[j].content.length; k< klen;k++) {
  if (data[i].content[j].content[k].key === key) {
  data[i].content[j].content[k].value = e.target.value
  }
  }
  }
  }
  this.setState({
  data
  },()=>{
  console.timeEnd('test1');
  })
  }
  方案2:最简单的,加个break
   handleChange2(e,key){
  console.time('test2');
  let data = this.state.data;
  for (let i = 0,flen = data.length; i < flen ;i++) {
  for (let j = 0,slen = data[i].content.length; j< slen; j++) {
  for (let k = 0,klen = data[i].content[j].content.length; k< klen;k++) {
  if (data[i].content[j].content[k].key === key) {
  data[i].content[j].content[k].value = e.target.value
  break;
  }
  }
  }
  }
  this.setState({
  data
  },()=>{
  console.timeEnd('test2');
  })
  }
  方案3:直接传递数组下标
   handleChange3(e,key) {
  console.time('test3');
  let data = this.state.data;
  data[key[0]].content[key[1]].content[key[2]].value = e.target.value;
  this.setState({
  data
  },() => {
  console.timeEnd('test3');
  })
  }
  方案4:把数组中的值拷贝一份出来做一个字典,每次改值都在字典中改
   handleChange4(e,key){
  console.time('test4');
  let dict = this.state.dict;
  dict[key] = e.target.value;
  this.setState({
  dict
  },() => {
  console.timeEnd('test4');
  })
  }
  理论分析
  理论上的时间复杂度
  方案1、2不用说了其实都是一样的,O(n^3)方案3理论上是O(1)方案4理论上是O(n),且需要额外的空间复杂度O(n)综合性能上的话应该是方案3 > 方案4 > 方案2 > 方案1
  开测
  为了保证测试结果,每次都修改3个输入框的值,每次都是新增输入3个同样的字符,废话不多说,直接测
  方案1
  方案2
  方案3
  方案4
  纳尼?居然都差不多?
  接下来用不同的浏览器测试,数据来源换成生成好的JSON(保住数据完全相同),增大数据量都试过,在浏览器不卡死能渲染的情况下,这几种情况下的渲染时间居然是不相上下。
  分析
  后来在每种方案调用的情况下都调用了一下console.time,发现4种方案消耗时间基本一致。就是说,方案1、2的遍历速度在我的电脑上遍历速度都非常快,导致了优化的效果并不明显。也就是说,在公司做的性能优化方案其实对于常见的电脑来说其实意义不大(测试的数据量已经大于公司的数据量了)。但是对于低端机器,又没有合适的工具可以进行测试。。。
  后话
  有心人可能发现我一开始的渲染代码中没有上key(故意删的),因为当React作diff时,只要子元素有key属性,便会去原v-dom树中相应位置(当前横向比较的层级)寻找是否有同key元素,比较它们是否完全相同,若是则复用该元素,免去不必要的操作。但是对于我们此种测试,上述操作反而是不必要的,因为我们数据是固定的,上key反而多做了一次遍历(上面说的都是我猜的原因),那么上了key之后的时间是多少呢?
  想了那么久的数据结构,结果发现主流的电脑都可以忽略这点优化了,心情复杂。。。有没有大神告知一下是测试方法有问题还是真的机子太高端了,在这种数据级的情况下优化是没多大必要的?
  
      上文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理。
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号