IMA-WorldHealth / bhima-1.X

A hospital information system for developing countries.
GNU General Public License v2.0
10 stars 14 forks source link

Posting Journal Feature: Multi-Threaded Support through Web Workers #808

Open jniles opened 9 years ago

jniles commented 9 years ago

Presently, the entire bhima application runs in a single thread. This means that the Angular $digest() loop, DOM creation, updates, and remove, $http requests, and array.forEach() loops must compete for processing power. The entire application waits for large operations, leading to UI freezes and glitches.

I propose that we move some of our heavy work out of the main thread and into other CPU threads by using Web Workers. Web Workers allow you to move large calculations, such as totaling, map()s, reduce()s, and filter()s, into a separate thread and allow the Angular process to keep the UI smooth and responsive. Furthermore, you can create a Web Worker from a Blob, which removes the requirement of having an extra script -- you can create them from just a function!

How does this work? With SlickGrid, the View and Model are separate already (DataView vs Grid), and so this proposal works really well. An action such as grid.onSort() will call the worker to sort. Here is some pseudo-code illustrating this process:

grid.onSort.subscribe(function (e, args) {
  ui.startLoadingIndicator();
  SortWorker({
    data : dataview.getItems(),
    column : args.sortCol.field,
    asc : args.sortAsc
  }).then(function (sortedData) {
    dataview.beginUpdate();
    dataview.setItems(sortedDate)
    dataview.endUpdate();
    ui.stopLoadingIndicator();
  });
});

All of this work is done completely outside of the main thread, allowing the user to continue to toggle modals, scroll up and down, click on buttons, and carry on as they wish.

This proposal goes along really well with the "Column-Aware Context Menu" proposal, since it allows us to do really ambitious data-munging on the client. For example, for strings, we can implement a "Similar to {{ value }}" filter, which loops through the entire dataset, looking computing the Levenshtein distance between the value and all others in the column.

Perhaps a more practical idea is to provide checkbox filters for columns with high numbers of duplicates, as show in the mockup below. By checking a checkbox, you allow it in your view, and unchecked ones are not allowed in the view. This type of operation is far too complex for a single threaded application because you would have to block the view with getting the unique column values, paint them into the context menu, then synchronously block the view while filtering on those the user checks or unchecks. However, with an asynchronous, non-blocking background thread, this is suddenly very doable.

I'm intensely curious to see what you all think. I believe that, if this work well, we can start to do some really powerful, Excel-like work in our grid on the client.

(CheckBox filters inspired by this link)