preface

While developing various processes for a company requirement (i.e., a 3 or 4 layer nested form data (all display layer input boxes)), I had a flash of insight and thought of some performance improvement solutions, but I didn’t actually test whether the performance really improved due to the lack of time (in fact, PROCRASTINATION). It was not until these days that I really tested it, and the result was beyond my expectation.

The data structure of the form

For the test, the data must not be used by the company, but to be close to the real data amount of the company, no more words, directly on the mock. js, configuration is as follows:

{
    "data|4": [{
        "title": "@ctitle(5)"."content|25": [{
            "title": "@ctitle(5)"."content|25": [{
                "key": "@string(6)"."title": "@ctitle(5)"."value": "@word(3)"}}}}]]]Copy the code

The above configuration is only a brief version, the actual development of the data and a lot of other information, but it does not affect my test.

The test code

We iterate over the data every time we modify the input value. What we measure is how long it takes to iterate through the set of numbers for each change. The first code shown is as follows:


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 The < 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> })} < / a >}Copy the code

There are four inputs, each corresponding to a different Onchange scheme:

  1. Option 1: No optimization
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'); })}Copy the code
  1. Option 2: Simplest, add a 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'); })}Copy the code
  1. Scheme 3: Pass array subscripts directly
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'); })}Copy the code
  1. Plan 4: Make a dictionary out of a copy of the values in the array, and change each value in the dictionary
handleChange4(e,key){
    console.time('test4');
    let dict = this.state.dict;
    dict[key] = e.target.value;
    this.setState({
      dict
    },() => {
      console.timeEnd('test4'); })}Copy the code

The theoretical analysis

O(n^3) scheme 3 is O(1) scheme 4 is O(n) in theory, and requires extra space complexity. In terms of overall performance, it should be Scheme 3 > Scheme 4 > Scheme 2 > Scheme 1

Open test

In order to ensure the test results, each time modify the value of 3 input boxes, each time is new input 3 same characters, nonsense not to say, directly test

Plan 1

Scheme 2:

Solution 3:

Solution 4:

What? Are they all the same?

I then tested it with different browsers, changed the data source to generated JSON (keeping the data exactly the same), and increased the amount of data, and the rendering times were almost the same in these cases without the browser being unable to render.

Analysis of the

Console. time was later called in each case, and it was found that the four schemes consumed roughly the same amount of time. That is to say, the traversal speed of scheme 1 and 2 is very fast on my computer, resulting in not obvious optimization effect. In other words, the performance optimizations made at the company don’t really mean much to the common computer (the amount of data tested is already larger than the amount of data at the company). But for low-end machines, there is no suitable tool to test…

The latter

React diff: If a child element has a key attribute, it will look for the same key element in the original V-DOM tree (the current level of horizontal comparison). If it does, it will reuse the same element. Eliminate unnecessary operations. However, for this kind of test, the above operation is not necessary, because our data is fixed, on the key instead of one more traversal (above mentioned is my guess), so after the key is how much time?

After thinking about the data structure for so long, the results found that mainstream computers can ignore this optimization, the mood is complicated… Is there a problem with the testing method or is there really no need to optimize at this data level because the machine is too high end?