Suspend rendering

How suspending improves performance

Within Handsontable any CRUD operation ends with a render. In most cases, this is considered an expected behavior - eventually, the table has to reflect the requested changes at some point.

However, sometimes you may find this mechanism slightly excessive - for example, you wrote a custom function that uses several CRUD operations. Those CRUD operations will call a render for each API method but essentially, you need only one render at the end which is sufficient to reflect the changes. In this case, you can treat those combined operations as a single action and let the render wait for them to complete. To do so you need to suspend the render (batch the operations).

This can improve the overall performance of the application. Batching several operations can decrease the number of renders, so any API call that ends with a render will benefit from this improvement. It results in less layout trashing, fewer freezes, and a more responsive feel.

There are several API methods you can use for suspending but the batch is the most universal one. It is a callback function - the render is executed after all operations provided inside of the body are completed. This is a recommended method as it is more safe and comfortable to use. You just need to place all operations you want to batch inside a closure. Handsontable takes care of the suspending and render a single time in the end.
The following snippet shows a simple example of a few operations batched. Three API operations are called one after another. Without placing them inside the batch callback each single operation would end with a render. Thanks to the batching feature you can skip two renders and end the whole action with one render at the end. This is more optimal, and the gain grows with the number of operations placed inside the batch.

// call the method on an instance
hot.batch(() => {
  // run the operations as needed
  hot.alter('insert_row', 5, 45);
  hot.setDataAtCell(1, 1, 'x');
  hot.selectCell(0, 0);
  // the render is executed right after all of the operations are completed
});

As mentioned - suspending the render results in better performance, this is especially visible for numerous operations batched. The diagram shows a comparison, the same operations were performed with (deep blue columns) and without the batch (light blue columns). The gain in speed of execution time increases with the number of operations batched.

batch_diagram

Note that there are other methods that can be used to batch operations, however they are slightly more advanced and should be used with caution. Flickering, glitches, or other visual distortion may happen when you forget to resume render after suspending it several times. Mixing methods of a render type with those focused on operations can also result in some unexpected behavior. Above all, batch should be sufficient in most use cases, and it is safe to work with.

API methods

There are several API methods which allow suspending:

  • batch
  • batchRender
  • batchExecution
  • suspendRender and resumeRender
  • suspendExecution and resumeExecution

By using these methods you can suspend:

  • rendering
  • execution
  • both rendering and the execution.

Term "rendering" refers directly to DOM rendering, the term "execution" refers to all operations that are different from DOM rendering. Currently only the indexes recalculation allows to postpone the process.

Methods which names start with batch* prefix, that is: batch,batchRender and batchExecution are recommended to be used as the first choice if you don't need to batch async operations.
Methods which names start with suspend* prefix, that is: suspendRender and suspendExecution are of the second choice - useful when you need to batch async operations. In essence they work the same as batch* methods but the render has to be resumed manually.

batch* methods

batch

This method supsends both rendering and other operations. It is universal and especially useful if you want to batch multiple API calls within the application.

hot.batch(() => {
  hot.alter('insert_row', 5, 45);
  hot.setDataAtCell(1, 1, 'x');

  const filters = hot.getPlugin('filters');

  filters.addCondition(2, 'contains', ['3']);
  filters.filter();
  hot.getPlugin('columnSorting').sort({ column: 1, sortOrder: 'desc' });
  // The table cache will be recalculated and table render will be called once after executing the callback
});

batchRender

The batchRender method is a callback function, excessive renders can be skipped by placing the API calls inside of it. The table will be rendered after executing the callback. It is less prone to errors as you don't have to remember about resuming the render. However, there is a drawback to this method: it doesn't support async operations.

hot.batchRender(() => {
  hot.alter('insert_row', 5, 45);
  hot.setDataAtCell(1, 1, 'x');
  // The table will be rendered once after executing the callback
});

batchExecution

The batchExecution is a callback function, excessive renders can be skipped by placing the API calls inside of it. The table will be rendered after executing the callback. It is less prone to errors as you don't have to remember about resuming the operations. However, there is a drawback to this method: it doesn't support async operations.

hot.batchExecution(() => {
  const filters = hot.getPlugin('filters');

  filters.addCondition(2, 'contains', ['3']);
  filters.filter();
  hot.getPlugin('columnSorting').sort({ column: 1, sortOrder: 'desc' });
  // The table cache will be recalculated once after executing the callback
});

suspend* and resume* methods

suspendRender and resumeRender
To suspend the rendering process you can use suspendRender method just before the actions you want to batch. This is a manual approach - after suspending you have to remember to resume the process with the resumeRender method.

hot.suspendRender(); // suspend rendering
hot.alter('insert_row', 5, 45);
hot.setDataAtCell(1, 1, 'x');
hot.resumeRender(); // remember to resume rendering

suspendExecution and resumeExecution

To suspend the rendering process you can use suspendExecution method just before the actions you want to batch. This is a manual approach - after suspending you have to remember to resume the process with the resumeExecution method.

hot.suspendExecution();
const filters = hot.getPlugin('filters');

filters.addCondition(2, 'contains', ['3']);
filters.filter();
hot.getPlugin('columnSorting').sort({ column: 1, sortOrder: 'desc' });
hot.resumeExecution(); // It updates the cache internally

Live demo of suspend feature

The following examples show how much the batch method can decrease the render time. Both of the examples share the same dataset and operations. The first one shows how much time lapsed when the batch method was used. You can run the second example to check how much it takes to render without the batch method.

Edit this page

Tutorial: Suspend rendering