I have a cpu intensive task that I need to run on the client. Ideally, I'd like to be able to invoke the function and trigger progress events using jquery so I can update the UI.
I know javascript does not support threading, but I've seen a few promising articles trying to mimic threading using setTimeout.
What is the best approach to use for this? Thanks.
Basically, what you want to do is to divide the operation into pieces. So say you have 10 000 items you want to process, store them in a list and then process a small number of them with a small delay between each call. Here's a simple structure you could use:
function performTask(items, numToProcess, processItem) {
var pos = 0;
// This is run once for every numToProcess items.
function iteration() {
// Calculate last position.
var j = Math.min(pos + numToProcess, items.length);
// Start at current position and loop to last position.
for (var i = pos; i < j; i++) {
processItem(items, i);
}
// Increment current position.
pos += numToProcess;
// Only continue if there are more items to process.
if (pos < items.length)
setTimeout(iteration, 10); // Wait 10 ms to let the UI update.
}
iteration();
}
performTask(
// A set of items.
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o'],
// Process two items every iteration.
2,
// Function that will do stuff to the items. Called once for every item. Gets
// the array with items and the index of the current item (to prevent copying
// values around which is unnecessary.)
function (items, index) {
// Do stuff with items[index]
// This could also be inline in iteration for better performance.
});
Also note that Google Gears has support to do work on a separate thread. Firefox 3.5 also introduced its own workers that do the same thing (although they follow the W3 standard, while Google Gears uses its own methods.)
I had a similar problem to solve recently where i needed to keep my UI thread free while crunching some data to display.
I wrote a library Background.js to handle a few scenarios: a sequential background queue (based on the WorkerQueue library), a list of jobs where each is called on every timer, and an array iterator to help break up your work into smaller chunks. Examples and code here: https://github.com/kmalakoff/background
Enjoy!
If you can enforce the browser to be used, or you otherwise already know it to be a new version of Firefox, you could use the new WebWorkers from Mozilla. It allows you to spawn new threads.
Depending on what your requirements are, you may get off easily by using Gears. Gears supports threads, which could do what you want.
As you mentioned, setTimeout is the other option. Depending on the type of your task, you can hand off each iteration of a loop to a separate setTimeout call with some spacing in between, or you may need to separate pieces of your main algorithm into separate functions which can be called one by one in a same manner as you'd call each iteration.
Great answer Kevin! I wrote something similar a few years back, though less sophisticated. Source code is here if anyone wants it:
http://www.leapbeyond.com/ric/jsUtils/TaskQueue.js
Anything with a run() method can be queued as a task. Tasks can re-queue themselves to perform work in chunks. You can prioritize tasks, add/remove them at will, pause / resume the entire queue, etc. Works well with asynchronous operations - my original use for this was to manage several concurrent XMLHttpRequests.
Basic usage is pretty simple:
var taskQueue = new TaskQueue();
taskQueue.schedule("alert('hello there')");
The header comments in the .js file provide more advanced examples.
Here is my solution to the problem, in case someone wants simple copy-pasteable piece of code:
var iterate = function (from, to, action, complete) {
var i = from;
var impl = function () {
action(i);
i++;
if (i < to) setTimeout(impl, 1);
else complete();
};
impl();
};
This is a very basic example of how to create threads in JavaScript.
Note that is is up to you to interrupt your thread functions (yeld instruction). If you want, you can use a setTimeout instead of my while loop to run the scheduler periodically.
Note also that this example only works with JavaScript version 1.7+ (firefox 3+)
you can try it here: http://jslibs.googlecode.com/svn/trunk/jseval.html
//// thread definition
function Thread( name ) {
for ( var i = 0; i < 5; i++ ) {
Print(i+' ('+name+')');
yield;
}
}
//// thread management
var threads = [];
// thread creation
threads.push( new Thread('foo') );
threads.push( new Thread('bar') );
// scheduler
while (threads.length) {
var thread = threads.shift();
try {
thread.next();
threads.push(thread);
} catch(ex if ex instanceof StopIteration) { }
}
The output is:
0 (foo) 0 (bar) 1 (foo) 1 (bar) 2 (foo) 2 (bar) 3 (foo) 3 (bar) 4 (foo) 4 (bar)
My strongest recommendation is to display a simple loading.gif during the operation. User often accepts some duration if they have been "told" that it could take some time.
Ajaxload - Ajax loading gif generator
use requestIdleCallback().
Then you will use the browsers idle time to process your task.
Sample found in:
https://developer.mozilla.org/en-US/docs/Web/API/Background_Tasks_API
there is a feature (experimental when I am writing):
https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback
seems not real multithread, but execute the task with low priority than the other (UI) tasks
so the solution can be:
make your task asynchronous
start your task with this
requestIdleCallback
loop using a setTimeout() with microtimes in your task, like between some main loop and his inner logic
the UI can update frequently in these timeouts
Seems this problem has been solved in node itself.
require child_process which is included in nodejs 0.10.4
Related
I'm using javascript loop (using setInterval) that runs through a list of search results, highlighting the search term by adding a css styled <span> around search hits as it goes. I'm using setInterval like this to release control of the browser while it does this.
In Chrome and Firefox this works well - even with a setInterval parameter of 10-20ms; and the user has full control of the browser (i.e. scrolling, clicking links etc.) while the results are rapidly highlighted:
mylooper = setInterval(function() {
// my functionality is here
},15); // 15ms
Unfortunately, when using the dreaded IE8, the browser locks up and takes a really long time to add the <span>'s and style the search results. It also takes a long time just to load the page in the first place - shortened a great deal when this script is removed.
So far I've tried:
changing the interval values (I've read that IE8 doesn't detect intervals of sub 15ms);
using setTimeout instead of setInterval;
removing the interval to check that this is in fact what is causing the slow-down (it is!); and
swearing about Internet Explorer a lot;
var highlightLoop;
var index = 0;
highlightLoop = setInterval(function () {
var regex = RegExp(regexPhrase, "gi"); // regexPhase created elsewhere
var searchResults = resultElements.eq(index).get(0); // run through resultElements which contain alll the nodes with search results in them.
findAndReplaceDOMText( // a function that does the searching and inserting of styling
regex,
searchResults,
function (fill, matchIndex) {
called = true;
var span = document.createElement("span");
span.className = "result-highlight";
span.innerHTML = fill;
return span;
}
);
if (index == resultElements.length || searchTermUpdated == true) { // stop interval loop when search term changes or we reach the end of results - variable set elsewhere.
searchTermUpdated = false;
clearInterval(highlightLoop); // stop the loop
}
index++
}
}, 50); // 50ms does not improve performance.
Any advice on workarounds for this kind of javascripting in IE would be massively appreciated. Thanks all.
I believe you may be able to improve the performance by tweaking findAndReplaceDOMText, and maybe its callback too. I suppose findAndReplaceDOMText appends the element returned by the callback to the DOM, from within a loop of all matches. If it's doing that inside a loop, try to move it outside the loop, and apply the all changes to the DOM at once. That should result in better performance, as repainting the page after each DOM update is expensive.
Try this recursive approach instead:
get a list of all elements to be acted upon into array X (one time cost)
while the array X has length, keep repeating the next actions
shift the first element off the array
process the single element
start this process again with the new array X (now Xn - 1 length) on a setTimeout
The code looks like this in general
function processArray(array) {
var element = array.shift();
processElement(element);
if (array)
setTimeout(function(){processArray(array);},15ms);
}
There might be something else to be done with this recursion, but it works fairly well in all browsers and never blocks, because you're only initiating the repeat when the last one has had time to finish.
I have some different Map/Reduces functions that I use in my project. But one is a lot different than the others since it requires a loop in the map functionality. And for each count in the loop, I send an emit.
What I have is this scenario (in the user collection):
"channels" : [
"Channel 1",
"Channel 2",
],
What I want to do is to count how many users each channel has. So for that I could use db.users.find({channels: "Channel 1"}).count() but unfortunately channels are dynamic which means I don't know all the possible channel names and it may well change in the future.
So I thought that a Map/Reduce job would sit just perfect. But the problem is that the first Reduce job I wrote calculated wrong. And the other where I used a query for each emit, would come to take forever (more than 3 hours before the ssh session shut down).
So now I'm stuck and I need help, preferably I would want to have a Map/Reduce job since it's more nice than a bunch of queries which is kind of slow to run in real time.
This is the latest Map and Reduce functions I wrote:
var map = function() {
if(this.channels) {
for(var i = 0, imax = this.channels.length; i<imax; i++) {
emit(this.channels[i], 1);
}
}
}
var reduce = function (key, values) {
var result = 0;
values.forEach(function (value) {
// had this before: result += 1;
result = db.users.find({'channels' : key}).count();
});
return result;
}
I knew that the reduce function was horrific but I just tried the best I could think of. I think my logic may seem wrong but I can't find a good solution. Now I'm thinking of just doing a bunch of queries on every page load, but it will be slow as hell.
Please help! :)
In your scenario the reduce function should look like this:
var reduce = function (key, values) {
var result = 0;
values.forEach(function (value) {
result += value;
});
return result;
}
Let me know if it is still not working and if it does please give an example of input and (incorrect) output.
MR is sometimes a bit slow. So you might want to check out the new aggregation framework coming with 2.2 (which i think is s currently in release phase).
See: http://docs.mongodb.org/manual/applications/aggregation/
Additionally you might need to speed up the queries via using proper indices. Or adding a user count to the channels and increasing/decreasing when the user joining/leaving a channel. Depends on your app's use case of course.
I have some JavaScript that I'm trying to benchmark the time it takes to execute.
The problem with this is that the for loop completes quickly, meanwhile the execution of the Item.save() method is not yet complete.
Any suggestions how to time this that takes into account the full execution time within the contents of the loop?
Thank you!
var start = new Date().getTime();
var Item = new Item();
for (i = 0; i < 500; i++) {
var item = {};
item.name = 5;
item.id = 10;
item.set = [];
Item.save(item, function (err, res) {
console.log(res);
});
}
var elapsed = new Date().getTime() - start;
console.log(elapsed);
EDIT: This is on a nodejs server.
Just use Chrome's profiling tools. They give you total insight into exactly how much CPU time every function call on your page is taking up:
http://code.google.com/chrome/devtools/docs/cpu-profiling-files/two_profiles.png
For Node, you can try node-inspector's experimental profiler.
The best way to handle this would be to modify the Item.save() function to take in the start time and then do your comparison at the very end. Or, implement a callback function (succes:) on Item.save().
The answer is simple: create a jsPerf test case. It allows running asynchronous or “deferred” tests.
Alternatively, you could use Benchmark.js and set up a deferred test case manually.
Don’t simply compare two new Date timestamps, as that only works for synchronous tests. (Also, this is not an accurate way of measuring things across all browsers and devices.)
I have a game I'm creating where lights run around the outside of a circle, and you must try and stop the light on the same spot three times in a row. Currently, I'm using the following code to loop through the lights and turn them "on" and "off":
var num_lights = 20;
var loop_speed = 55;
var light_index = 0;
var prevent_stop = false; //If true, prevents user from stopping light
var loop = setTimeout(startLoop, loop_speed);
function startLoop() {
prevent_stop = false;
$(".light:eq(" + light_index + ")").css("background-color", "#fff");
light_index++;
if(light_index >= num_lights) {
light_index = 0;
}
$(".light:eq(" + light_index + ")").css("background-color", "red");
loop = setTimeout(startLoop, loop_speed);
}
function stopLoop() {
clearTimeout(loop);
}
For the most part, the code seems to run pretty well, but if I have a video running simultaneously in another tab, the turning on and off of the lights seems to chug a bit. Any input on how I could possibly speed this up would be great.
For an example of the code from above, check out this page: http://ericditmer.com/wheel
When optimizing the thing to look at first is not doing twice anything you only need to do once. Looking up an element from the DOM can be expensive and you definitely know which elements you want, so why not pre-fetch all of them and void doing that multiple times?
What I mean is that you should
var lights = $('.light');
So that you can later just say
lights.eq(light_index).css("background-color", "red");
Just be sure to do the first thing in a place which keeps lights in scope for the second.
EDIT: Updated per comment.
I would make a global array of your selector references, so they selector doesn't have to be executed every time the function is called. I would also consider swapping class names, rather than attributes.
Here's some information of jQuery performance:
http://www.componenthouse.com/article-19
EDIT: that article id quite old though and jQuery has evolved a lot since. This is more recent: http://blog.dynatrace.com/2009/11/09/101-on-jquery-selector-performance/
You could try storing the light elements in an array instead of using a selector each time. Class selectors can be a little slow.
var elements = $('.light');
function startLoop() {
prevent_stop = false;
$(elements[light_index]).css('background-color', '#fff');
...
}
This assumes that the elements are already in their intended order in the DOM.
One thing I will note is that you have used a setTimeout() and really just engineered it to behave like setInterval().
Try using setInterval() instead. I'm no js engine guru but I would like to think the constant reuse of setTimeout has to have some effect on performance that would not be present using setInterval() (which you only need to set once).
Edit:
Curtousy of Diodeus, a related post to back my statement:
Related Stack Question - setTimeout() vs setInterval()
OK, this includes some "best practice" improvements, if it really optimizes the execution speed should be tested. At least you can proclaim you're now coding ninja style lol
// create a helper function that lend the array reverse function to reverse the
// order of a jquery sets. It's an object by default, not an array, so using it
// directly would fail
$.fn.reverse = Array.prototype.reverse;
var loop,
loop_speed = 55,
prevent_stop = false,
// prefetch a jquery set of all lights and reverses it to keep the right
// order when iterating backwards (small performance optimization)
lights = $('.light').reverse();
// this named function executes as soon as it's initialized
// I wrapped everything into a second function, so the variable prevent_stop is
// only set once at the beginning of the loop
(function startLoop() {
// keep variables always in the scope they are needed
// changed the iteration to count down, because checking for 0 is faster.
var num_lights = light_index = lights.length - 1;
prevent_stop = false;
// This is an auto-executing, self-referencing function
// which avoids the 55ms delay when starting the loop
loop = setInterval((function() {
// work with css-class changing rather than css manipulation
lights.eq( light_index ).removeClass('active');
// if not 0 iterate else set to num_lights
light_index = (light_index)? --light_index:num_lights;
lights.eq( light_index ).addClass('active');
// returns a referenze to this function so it can be executed by setInterval()
return arguments.callee;
})(), loop_speed);
})();
function stopLoop() {
clearInterval(loop);
}
Cheers neutronenstern
This question already has answers here:
What is the JavaScript version of sleep()?
(91 answers)
Closed 9 years ago.
Yes, I know - that question has thousands of answers. please, don't tell me about setTimeout method because - yes, everything is possible with that but not so easy as using sleep() method.
For example:
function fibonacci(n) {
console.log("Computing Fibonacci for " + n + "...");
var result = 0;
//wait 1 second before computing for lower n
sleep(1000);
result = (n <= 1) ? 1 : (fibonacci(n - 1) + fibonacci(n - 2));
//wait 1 second before announcing the result
sleep(1000);
console.log("F(" + n + ") = " + result);
return result;
}
if you know how to get the same result using setTimeout - tell me ;) fibanacci is pretty easy task, because there aren't more than 2 recursions, but how about n-recursions (like fib(1) + fib(2) + .. + fib(n)) and sleep after every "+"? Nah, sleep would be muuuuuch easier.
But still I can't get working example of implementing it. while (curr - start < time) { curr = (...) } is tricky, but it won't work (just stops my browser and then throw all console logs at once).
The question is asking how to implement sleep() in JavaScript, right?
function sleep(ms) {
var start = new Date().getTime(), expire = start + ms;
while (new Date().getTime() < expire) { }
return;
}
I just tested it like so:
console.log('hello');
sleep(5000);
console.log('world');
Works for me.
(As a meta comment: I landed here because I have a particular need for this function. Such needs do come up when you need to block while waiting for a value. Even in JavaScript.)
I dont fully understand what you're asking, but I'm going to answer this part:
if you know how to get the same result
using setTimeout - tell me
The fundamental difference is that sleep (as used in many other languages) is synchronous, while setTimeout (and many other JavaScript-concepts, like AJAX for example) are asynchronous. So, in order to rewrite your function we have to take this into account. Mainly, we have to use a callback to fetch the "return value", rather than an actual return-statement, so it will be used like this:
fibonacci(7, function(result) {
// use the result here..
});
So, as for the implementation:
function fibonacci(n, callback) {
console.log("Computing Fibonacci for " + n + "...");
var result = 0;
var announceAndReturn = function() {
setTimeout(function() {
// wait 1 second before announcing the result
console.log("F(" + n + ") = " + result);
callback(result); // "returns" the value
}, 1000);
};
// wait 1 second before computing lower n
setTimeout(function() {
if (n <= 1) {
result = 1;
announceAndReturn();
}
else {
var resultsLeft = 2;
var handler = function(returned) {
result += returned;
resultsLeft--;
if (resultLeft == 0)
announceAndReturn();
}
fibonacci(n-1, handler);
fibonacci(n-2, handler);
}
}, 1000);
}
I would also like to point out that, no, this is not an easier solution than using sleep. Why? Because this code is asynchronous and that's simply more complicated than synchronous code for what most people are used to. It takes practice to start thinking in that way.
The upside? It allows you to write non-blocking algorithms that outperforms their synchronous counterparts. If you haven't heard of Node.js before, you could check it out to further understand the benefits of this. (Many other languages have libraries for dealing with async IO as well, but as long as were talking about JavaScript..)
The trouble with a sleep() type function within a browser (or any other GUI environment for that matter) is that it is an event-driven environment, and wouldn't be able to sleep() in the way you're describing it.
The setTimeout() method works because it is creating an event, and setting the trigger for that event to be a point in time. Therefore the system can give over control of the waiting to the event handler and Javascript itself is free to carry on doing other things.
In the web browser, virtually everything works this way. Mouse click/hover/etc functions are event triggers. Ajax requests don't sit and wait for the response from the server; they set an event to trigger when the response is received.
Time based actions are also done with event triggers, using functions like setTimeout().
This is how it's done. In fact this is how it's done in pretty much any well-written GUI application, because all GUI interfaces must be able to respond to events such as mouse clicks virtually instantly.
A Javascript sleep() function (especially the way it's been implemented in another answer here!) would basically have the effect burn up your CPU cycles while it waited for the clock. The sleep() would remain the active process, meaning that other events may not be processed straight away - which means your browser would appear to stop responding to mouse clicks, etc for the duration of the sleep. Not a good thing.
setTimeout() is the way to go. There is always a way to do it; the resulting code may not be neat and linear like your example code, but event-driven code very rarely is linear - it can't be. The solution is to break the process down into small functions. you can even embed the subsequent functions inside the setTimeout() call, which may go some way to helping you keep your code at least having some appearance of being linear.
Hope that helps explain things a bit for you.
Just use a better algorithm without loops or recursion, and avoid the need for setTimeout() / sleep().
function fibonacci(n) {
return Math.round(Math.pow((Math.sqrt(5) + 1) / 2, Math.abs(n)) / Math.sqrt(5)) * (n < 0 && n % 2 ? -1 : 1);
}
Usage example:
// Log the first 10 Fibonacci numbers (F0 to F9) to the console
for (var i = 0; i < 10; i++) {
console.log(fibonacci(i));
}
Why do you want to 'sleep' while computing anything? Sleeping for any time is nearly always a bad idea in any language. It essentially tells the thread to stop doing anything for that period of time.
So, in a language like javascript that only has one thread (forgetting 'web workers'), what benefit would you reap for pausing ALL computation? It's a bad idea, forget it.
Now to the problem that you've written, though I don't think this is your actual problem. Why do you want to pause for a second while computing this sequence? Even to compute the first 6 numbers in the sequence, it's going to take 8 or so seconds. Why? What possible reason is there to pause for a second between recursive calls? Stop it. Remove it.
If you want to just yield the final result a second after it completes, then use setTimeout with a function uses the answer in some way.
function fib(n) {
...
result = fib();
...
setTimeout(function() {
console.log("Fib for " + n + " is " + result);
},1000);
}
Do not try to implement 'sleep'. Do not pause during computation.