I noticed a question the other day ( Decreasing the use of the Javascript processor ), and I was intrigued.
In fact, the guy wanted to encrypt some files by nature. Obviously, all this will close the browser in one go.
His first idea was to do this in pieces of about 1 kilobyte of string at a time, and then pause for X ms so that it allows the user to continue interacting with the page between processing. He also considered using webWorkers (the best idea), but obviously this is not a cross browser.
Now I really don't want to go into why this is probably not a good idea in javascript. But I wanted to see if I could come up with a solution.
I remembered watching a Douglas Crockford video in js conf . The video was related to node.js and the event loop. But I remembered that he was talking about breaking long functions down into separate pieces, so the newly called function goes to the end of the event loop. Instead of clogging an event loop with a lengthy task, preventing anything else.
I knew this decision was worthy of my investigation. As an interface designer, I never encountered very big tasks in JS and really wanted to know how to break them down and how they work.
I decided to try a recursive function that calls itself inside setTimeout 0ms. I realized that this would provide breaks in the event loop for something else that was supposed to happen during its launch. But I also thought that while nothing is happening, you will get the maximum calculation.
Here is what I came up with.
(I'm going to apologize for the code. I experimented in the console, so it was quick and dirty.)
function test(i, ar, callback, start){ if ( ar === undefined ){ var ar = [], start = new Date; }; if ( ar.length < i ){ ar.push( i - ( i - ar.length ) ); setTimeout(function(){ test( i, ar, callback, start); },0); } else { callback(ar, start); }; }
(You can paste this code into the console and it will work)
Essentially, what the function does is, it takes a number, creates an array and calls itself, and array.length < number still pushes the counter into the array. It passes the array created on the first call of all subsequent calls.
I tested it and it seemed to work exactly as intended. Only its performance is rather poor. I checked it with.
(again, this is not a sexual code)
test(5000, undefined, function(ar, start ){ var finish = new Date; console.log( ar.length, 'timeTaken: ', finish - start ); });
Now, I obviously wanted to know how long it took to complete, the code above took about 20 seconds. Now it seems to me that it shouldn't take 20 seconds for JS to calculate up to 5000. Add to the fact that it does some calculations and processing to input the elements into an array. But still the 20s are a little cool.
So, I decided to create several at the same time to find out how this affected browser performance and computing speed.
(code does not get sexier)
function foo(){ test(5000, undefined, function(ar, start ){ var finish = new Date; console.log(ar.length, 'timeTaken: ', finish - start, 'issue: 1' ) }); test(5000, undefined, function(ar, start ){ var finish = new Date; console.log(ar.length, 'timeTaken: ', finish - start, 'issue: 2' ) }); test(5000, undefined, function(ar, start ){ var finish = new Date; console.log(ar.length, 'timeTaken: ', finish - start, 'issue: 3' ) }); test(5000, undefined, function(ar, start ){ var finish = new Date; console.log(ar.length, 'timeTaken: ', finish - start, 'issue: 4' ) }); test(5000, undefined, function(ar, start ){ var finish = new Date; console.log(ar.length, 'timeTaken: ', finish - start, 'issue: 5' ) }); };
So, five in total work simultaneously and do not cause browser freezes.
after the completion of the process, all results are returned almost at the same time. to complete them, it took about 21.5 s. This is only 1.5s slower than one. But I moved the mouse around the window on elements that had effects :hover to make sure the browser was still responding, so this might reflect some of the overhead for 1.5 seconds.
Since these functions obviously work in parallel, more computing juice remains in the browser.
Can someone explain what is happening here and give detailed information on how to improve such features?
Just go crazy, I did it.
function foo(){ var count = 100000000000000000000000000000000000000; test(count, undefined, function(ar, start ){ var finish = new Date; console.log(ar.length, 'timeTaken: ', finish - start, 'issue: 1' ) }); test(count, undefined, function(ar, start ){ var finish = new Date; console.log(ar.length, 'timeTaken: ', finish - start, 'issue: 2' ) }); test(count, undefined, function(ar, start ){ var finish = new Date; console.log(ar.length, 'timeTaken: ', finish - start, 'issue: 3' ) }); test(count, undefined, function(ar, start ){ var finish = new Date; console.log(ar.length, 'timeTaken: ', finish - start, 'issue: 4' ) }); test(count, undefined, function(ar, start ){ var finish = new Date; console.log(ar.length, 'timeTaken: ', finish - start, 'issue: 5' ) }); };
It worked all the time when I wrote this post, and is still ready for it. The browser does not complain or hang. I will add a completion time as soon as it ends.