In most cases you will also need to include a callback so that the program using your function can make use of its results. This is not difficult to add, and a final version of the function complete with a callback parameter and a suitable callback function is:
computePiAsync(displayResult);
function displayResult(pi){
result.innerHTML = pi;
}
function computePiAsync(callback) {
var state = {};
state.k = 0;
state.pi = 0;
window.addEventListener("message",computePi, false);
function computePi() {
if (state.k >= 10000000){
callback(state.pi);
return;
};
var i;
for (i = 0; i < 1000; i++) {
state.k++;
state.pi += 4 * Math.pow(-1, state.k + 1) / (2 * state.k - 1);
}
window.postMessage("fireEvent", "*");
}
window.postMessage("fireEvent", "*");
}
Avoiding State – Yield
Final version in book
Summary
If you need to make your own long running functions non-blocking then you can either use another thread or split the computation into short sections.
Threads are more powerful, but not all browsers support them and they can be difficult to implement.
The basic idea in creating a non-blocking function without threads is to make them run in small chunks of time, releasing the UI thread often enough to keep the UI responsive.
The main problem is is to keep the state of the computation so that it can be resumed after it has released the UI thread.
In most cases you need to write the function using a state object to record the important information so that the function resumes from where it left off.
To schedule the next run of the function you can use setTimeout or postMessage to place the function on the event queue.
An alternative way to keep the state of the function is to write it as a generator and use the yield instruction to pause the function and next to resume it.
If you use yield the system will look after the state for you and you can even pause for loops and generally write the function without having to worry about restoring state.