Preventing Code Blocking with a Timer and a Callback
You have a piece of code that can be time consuming, and you don’t want to block the rest of the code from processing while waiting for it to finish. But you do need to perform some functionality when the time-consuming function is finished.
Solution
Use a callback function in conjunction with setTimeout() with timer set to zero (0).
factorial() is called twice: once with a value of 3 and once with a
value of 4. In factorial(), the value of the parameter is printed out to the console in
each iteration. In noBlock(), a setTimeout() is used to call factorial(), passing to it
its first parameter. In addition, an optional second parameter is called if the second
parameter is a function. noBlock() is called twice with other JavaScript statements
printing nonessential text to the console inserted preceding, between, and after the two
calls. It’s also called a third time, in the callback for the very first call to noBlock().
Using a timer and callback function to prevent code blocking
function factorial(n) { console.log(n); return n == 1 ? 1 : n * factorial(n -1); } function noBlock(n, callback) { setTimeout(function() { var val = factorial(n); if (callback && typeof callback == 'function') { callback(val); } },0); } console.log("Top of the morning to you"); noBlock(3, function(n) { console.log('first call ends with ' + n); noBlock(n, function(m) { console.log("final result is " + m); }); }); var tst = 0; for (i = 0; i < 10; i++) { tst+=i; } console.log("value of tst is " + tst); noBlock(4, function(n) { console.log("end result is " + n); }); console.log("not doing too much");
The result of this application run in jsBin is the following output:
"Top of the morning to you" "value of tst is 45" "not doing too much" 3 2 1 "first call ends with 6" 4 3 2 1 "end result is 24" 6 5 4 3 2 1 "final result is 720"
Even though the calls to noBlock() occur before a couple of the extraneous con sole.log() calls, the function’s process doesn’t block the other JavaScript from pro‐ cessing. In addition, the calls to callBack() are processed in the proper order: the two outer calls complete, before the second one invoked in the callback for the first call to callBack() is processed.
EXPLAIN
Regardless of the underlying system or application, JavaScript is not multithreaded: all processes are run on a single thread of execution. Normally this isn’t an issue except for those times when you’re running an extremely lengthy bit of code and you don’t want to block the rest of the application from finishing its work. In addition, you may want to hold off on running another piece of code until after the lengthy code is finished.
One solution for both programming challenges is to use a JavaScript timer in conjunc‐ tion with a callback function—a function passed as parameter to another function, and called within that function in certain circumstances and/or at the end of a process. When a JavaScript timer event occurs, like any other asynchronous event in JavaScript, it’s added to the end of the event queue rather than getting pushed into the queue im‐ mediately.
Exactly how and where it enters the queue varies by browser and application environment, but generally, any functionality associated with the timer event is pro‐ cessed after any other functionality within the same queue. This can be a bit of an annoyance if you want a process to run exactly after so many seconds, but the functionality can also be a handy way of not blocking an application while waiting for a time-intensive event. By setting the setTimeout() timer to zero (0), all we’ve done in the solution is to create an event that’s pushed to the end of the execution queue.
By putting the time-intensive event into the timer’s process, we’re now no longer blocking, while waiting for the process to complete And because we usually want to perform a final operation when a time-consuming process finishes, we pass a callback function to the timer process that’s called only when the process is ended. In the program output, the three outer console.log() calls are processed immediately, as is the outer loop within the program execution queue:
"Top of the morning to you" "value of tst is 45" "not doing too much"
The next event in the queue is the first noBlock() function call, where the code called factorial() logged its activity as it ran, followed by a call to the callback function logging the function’s result:
3 2 1 "first call ends with 6"
The second call to callBack() operated the same way and again factorial() logged its activity, and the callback logged the result:
4 3 2 1 "end result is 24"
Only then is the third call to callBack(), invoked in the callback function for the first callBack(), and using the end result of the first function call:
6 5 4 3 2 1 "final result is 720"
No comments:
Post a Comment