|Written by Ian Elliot|
|Monday, 05 November 2018|
Page 2 of 3
A Piece of Pi
As a simple example, suppose you want to compute pi to a few digits using the series:
pi=4*(1-1/3+1/5-1/7 ... )
This is very easy to implement, we just need to generate the odd integers but to get pi to a reasonable number of digits you have to compute a lot of terms.
The simple-minded synchronous approach is to write something like:
where the DOM elements are provided by:
The intention is to display the progress of the calculation by changing the text displayed in the two divs each time through the for loop.
If you try it out what you will find is that the UI freezes for some minutes and nothing is displayed in the web page until the loop finishes and the UI thread is freed to tend to the UI.
This is an example of an unacceptable function that monopolizes the UI thread at the expense of the UI.
To keep the UI responsive, and in this case to see the intermediate results, we have to turn the calculation into an asynchronous function using setTimeout. We do this by breaking the calculation in small chunks – say 1000 iterations each. To do this we need a state object that records the state of the calculation so that it can be resumed:
The function is now going to perform 1000 iterations and then update the text in the divs.
To enable the UI to stay responsive, the function then terminates, but not before setting itself up in the event queue ready to perform another 1000 iterations after the UI has been updated:
Notice the final setTimeout which ensures that the function restarts.
If you run this version of the computation you will find that not only does the UI remain responsive, you get to see the intermediate values as the calculation proceeds.
Notice that the computePi function is now almost non-blocking in that it returns after doing 1000 iterations.
Final version in book
We have already discovered in Chapter Two that the problem with using setTimeout is that it is slow. It can take 4 to 5 milliseconds to get the function that computes Pi restarted. The solution in most cases is to use the postMessage method as described in Chapter Two which has a much smaller overhead.
If you want to make use of the postMessage method and the message event for a zero delay addition to the event queue then the previous function can be rewritten as:
You can use the same technique to turn nearly any long running computation into an asynchronous procedure.
All you have to do is break the computation down into small parts and preserve the state of the computation at the end of each chunk so that it can be restarted. Write the function so that it takes the state object and continues the computation.
This is always possible, even if the task isn't to sum a mathematical series.
For example, if you want to perform a complex database operation, simply save the point in the transaction that you have reached.
|Last Updated ( Saturday, 10 November 2018 )|