kosker kosker - 2 months ago 7
React JSX Question

Performance of function expression inside render function

Is there any performance difference between defining a function inside

render
function or defining it in the class scope?

render
function scope:


render() {
const renderItem = (item) => (<li>{item.name}</li>);

return (<ul>
{this.props.itemList.map((item) => renderItem(item))}
</ul>);
}


class
scope:


export default class MyComponent extends React.Component {
const renderItem = (item) => (<li>{item.name}</li>);

render() {
return (<ul>
{this.props.itemList.map((item) => this.renderItem(item))}
</ul>);
}

}

Answer

Yes, somehow there's a difference of performance.

But this difference is so so so so minimal, that you can even notice or tell what is the difference.

The thing is, when you define the renderItem inside the render method, each time that the render method is called, the renderItem function will be recreated. In the other way, renderItem is defined only once in a life.

Because of that you can think that the "outside" method will be faster. But the thing is, in the "inside" method, the renderItem will be created only once per call. So if you have, for example, 1 million items to render, the "bottleneck" of the whole proccess will be the map itself, and not the creation of the renderItem method, gotcha?

But for test, I build this sample, to test both methods, insideFunction and outsideFunction. You can copy and run in your browser.

To test, you can run bench(10000) to see how much time both methods would take with an array with 10000 elements (in my computer, the average time for this size is around 0.05~0.07 seconds.

You can also run several bench tests and see the output average, with: nBenchs(10, 10000), run 10 bench(10000) tests.

Conclusion: In my computer, running tests with array with 1 million positions, I got something around 7 seconds average, for both methods. Running this several times, in most cases, the "outside" method as half second faster that "inside". But keep this in mind, if you have a code that takes 7 seconds to return the output to the user, you should start thinking in other alternatives to decrease this value (like showing parts of the result first and faster). If you're building an aplication that handle with that amout of data and have heavy proccess algorithms (which is not common in web/react applications), then every action that save you 7% of the time (half second of seven, in this case) are precious.

(function() {
  function renderItem(text) {
    let item = document.createElement('li');
    item.innerHTML = text;

    return item;
  }
  function outsideFunction(array) {
    return array.map(renderItem);
  }

  // exponse outsideFunction
  window.outsideFunction = outsideFunction;
})();

(function() {
  function insideFunction(array) {
    function renderItem(text) {
      let item = document.createElement('li');
      item.innerHTML = text;

      return item;
    }

    return array.map(renderItem);
  }

  // exponse insideFunction
  window.insideFunction = insideFunction;
})();

// just build an array with n elements
function buildArray(n) {
  let testArray = [];
  for(let i=0; i<n; i++) {
    testArray.push(`Text with index ${i}`);
  }

  return testArray;
}

// run nb test benchs with an array with n elements
function nBenchs(nb, n) {
  let Ocount = 0, Icount = 0;
  let result;

  for(let i=0; i<nb; i++) {
    result = bench(n);

    Ocount += result.Oend;
    Icount += result.Iend;
  }

  // output the average
  console.log(`outsideFunction average: ${Ocount/(nb*1000)} seconds`);
  console.log(`insideFunction average: ${Icount/(nb*1000)} seconds`);
}

// run a test bench with an array with n elements
function bench(n) {
  n = n || 100;

  let testArray = buildArray(n);
  let start, Oend, Iend;

  start = new Date();
  outsideFunction(testArray);
  Oend = ((new Date())-start);

  console.log(`outsideFunction: ${Oend/1000} secods`);

  start = new Date();
  insideFunction(testArray);
  Iend = ((new Date())-start);

  console.log(`insideFunction: ${Iend/1000} secods`);

  return { Oend, Iend };
}