JavaScript execution hangs page momentarily - javascript

I have a web application which uses jQuery/JavaScript heavily. It holds a large array in memory, and the user filters it by typing in a textbox.
Problem: When the filtering algorithm runs, the application becomes non-responsive and the browser may even ask the user whether to let the script continue.
Optimally, I would like the filter function to run in a separate thread, to avoid non-responsiveness. Is this possible in any way? Alternatively, I would like to show a rotating hourglass or similar, but browsers seem unable to display animated GIFs when running heavy scripts.
What is the best way of attacking the problem?

Browsers execute scripts in the main event processing thread. This means any long running scripts can holdup the browser queue.
You should split your filter logic into chunks and run them on timeout callback's. You may use a gap of 0 mills between executions. 0 milli's is just a suggestion to the browser, but the browser will use the gap between subsequent callbacks to clear its event queue. Timeout's is generally how long running scripts are ought to be executed in the browser environment to prevent the page from "hanging".

This type of job is what Web Workers were designed for, support is patchy, but improving.

Expanding on my comment from earlier, given that you are processing an array you are probably using a for loop. You can easily refactor a simple for loop to use setTimeout() so that the work is broken up into chunks and the browser gets a chance to handle screen paints and user interaction between each chunk. Simple example:
// Generic function to execute a callback a given number
// of times with a given delay between each execution
function timeoutLoop(fn, startIndex, endIndex, delay) {
function doIteration() {
if (startIndex < endIndex){
fn(startIndex++);
setTimeout(doIteration, delay);
}
}
doIteration();
}
// pass your function as callback
timeoutLoop(function(i) {
// current iteration processing here, use i if needed;
}, 0, 100, 0);
Demo: http://jsfiddle.net/nnnnnn/LeZxM/1/
That's just something I cobbled together to show the general idea, but obviously it can be expanded in various ways, e.g., you might like to add a chunkSize parameter to timeoutLoop() to say how many loop iterations to do in each timeout (adding a conventional loop around the call to fn()), etc.

Related

Is there any impact of having a script running x seconds in the browser?

I've created a script that runs every 1 second looking for a change in a value. Consider the code bellow:
setInterval(function() {
var inputOne = jQuery('#0_img_file');
var inputTwo = jQuery('.0_img-file').attr('src');
return function() {
if (inputOne.val() !== inputTwo) {
jQuery('.0_img-file').attr('src', inputOne.val());
}
}
}(), 1000);
So heres my question, could this script affect the site experience to the user or any kind of other stuff am not aware of?
I know there is functions in jquery like onChange, change etc but it only works if the user changes the value automatically, I've noticed it does not capture changes if other scripts change the value of an input.
First of all your code runs 10 times per second, not once. However, your browser is likely running on a computer with at least 2 multigigahertz cores with hyperthreading, megabytes of caching on board and you name it. So no, repeating a trivial task every 100ms (or 1s) is not going to noticeably slow down your browser, JS is usually rather fast.
Just don't run 100 jobs like this, you will start to feel it. And of course, you should just hook onto events of the scripts modifying the values, instead of polling for changes, which should be possible just fine with Javascript - due to its prototyped nature it's trivial to plug into existing code.
I've noticed it does not capture changes if other scripts change the value of an input.
That's because you probably use .attr('value', something) or .attr('checked', true') instead of .val(something) and .prop('checked', true).
So heres my question, could this script affect the site experience to the user or any kind of other stuff am not aware of?
Of course it can. Especially if the script make some heavy operations. Many browsers execute Javascript in only one thread. So when your script start, the browser will freeze during it's execution. If you have only one light script, it's ok. But if you abuse of this method, you will have some performances problems.
Well, I think the site will be little slower. The script calls a function every 1 second, so it will not have much problem on good computers. Besides, not everyone has good computers. Some users uses slow computers will have problem in perfomance, so usinh other way is needed.

Waiting in JavaScript beyond wrapping everything in setTimeout

So, I'm creating a bot to play a video game online (completely legally, there's a server for bot competitions, don't worry). The code is in JavaScript, which I'm just picking up now, and I'm having trouble telling the bot to do something, then wait either by time or by condition until doing something else.
So far, I'm simply wrapping everything in gigantic setTimeout commands, but this is extremely inelegant.
There's not too much code that's relevant to post, but essentially I've made up a lot of code that does things like move to a specific location, brake, chase another player, etc. Most work with a recursive setTimeout command - press certain buttons, reset variables, then start the function again if the condition isn't met. If I want to move to a specific location then brake when I finish with that, generally I'd put code likes this:
moveTarget(target);
brake();
[...Execute rest of code...]
However, JavaScript executes both of these commands at the same time, which obviously doesn't work very well. Is there a way to make something more like this (Or the equivalent with a condition instead of a specified time):
moveTarget(target);
wait3Seconds();
brake();
[...Execute rest of code...]
Without needing to do this:
moveTarget(target);
setTimeout(function(){
brake();
[...Execute rest of code...]
},3000);
Given how many of these situations I'll have, my code will end up looking like a gigantic mess of nested setTimeouts, which is not very pretty. Is there a better way? I'm already using JQuery, so I'm perfectly willing to use that if necessary.
A little background...
JavaScript does not handle concurrency in the same way as other programming languages you may be used to. Instead, JavaScript has only the one main thread, and instead has a queue for registering then handling events in order as they occur.
For this reason, it is very important to not do things that would block the thread for long periods of time (like a function such as Thread.sleep() would do). That is why you instead should use setTimeout or setInterval for things like this.
You could always create a custom sleep function to write code in the style you are requesting. This might be something like:
function sleep(millis) {
var startTime = Date.now();
while (Date.now() < startTime + millis) {}
}
But this would be VERY, VERY BAD. This would freeze the page while this sleep function is running.
Back to your problem...
You basically need to refactor your code to be more "eventful". Rather than having large, linear chunks of code within the same block, you should write your JavaScript code to use callbacks and timeouts.
So the last code block you showed is really the paradigm you should be following with JavaScript:
moveTarget(target);
setTimeout(function(){
brake();
[...Execute rest of code...]
},3000);
However, you can certainly clean things up a LOT, if instead of [...Execute rest of code...], you split that apart into other functions and call them from within your setTimeout callback. Of course, keeping your code blocks small and concise is a good rule of thumb in any programming language.
You might also interested in checking out the request animation frame function.
There isn't really a better way to do that. The reason is that any sort of waiting is going to trigger a task that goes into the task queue. Since javascript is single threaded, it has to use these task queues and as a result it will just keep on executing instructions past the setTimeout if instructions are present.
In order to execute code after your delay, it has to be in the timeout callback or it will execute immediately.
You could do this if you created all of your methods in a chain that had a wait command, similar to the jQuery queue system.
$("<div>").queue(function(next){
// do a
a();
next();
}).delay(3*1000).queue(function(next){
// after 3 seconds do b
b();
next();
}).delay(3*1000).queue(function(next){
// after 3 more seconds do c
c();
next();
}).dequeue(); //.dequeue() starts it, only has to be called to make a queue that isn't currently running begin.
so all you would have to do is maintain the same chain and keep adding to it.

Call setTimeout without delay

Quite often see in JavaScript libraries code like this:
setTimeout(function() {
...
}, 0);
I would like to know why use such a wrapper code.
Very simplified:
Browsers are single threaded and this single thread (The UI thread) is shared between the rendering engine and the js engine.
If the thing you want to do takes alot of time (we talking cycles here but still) it could halt (paus) the rendering (flow and paint).
In browsers there also exists "The bucket" where all events are first put in wait for the UI thread to be done with whatever it´s doing. As soon as the thread is done it looks in the bucket and picks the task first in line.
Using setTimeout you create a new task in the bucket after the delay and let the thread deal with it as soon as it´s available for more work.
A story:
After 0 ms delay create a new task of the function
and put it in the bucket. At that exact moment the UI thread is busy
doing something else, and there is another tasks in the bucket
already. After 6ms the thread is available and gets the task infront
of yours, good, you´re next. But what? That was one huge thing! It has
been like foreeeeeever (30ms)!!
At last, now the thread is done with that and comes and gets your
task.
Most browsers have a minimum delay that is more then 0 so putting 0 as delay means: Put this task in the basket ASAP. But telling the UA to put it in the bucket ASAP is no guarantee it will execute at that moment. The bucket is like the post office, it could be that there is a long queue of other tasks. Post offices are also single threaded with only one person helping all the task... sorry customers with their tasks. Your task has to get in the line as everyone else.
If the browser doesn´t implement its own ticker, it uses the tick cycles of the OS. Older browsers had minimum delays between 10-15ms. HTML5 specifies that if delay is less then 4ms the UA should increase it to 4ms. This is said to be consistent across browsers released in 2010 and onward.
See How JavaScript Timers Work by John Resig for more detail.
Edit: Also see What the heck is the event loop anyway? by Philip Roberts from JSConf EU 2014. This is mandatory viewing for all people touching front-end code.
There are a couple of reasons why you would do this
There is an action you don't want to run immediately but do want to run at some near future time period.
You want to allow other previously registered handlers from a setTimeout or setInterval to run
When you want to execute rest of your code without waiting previous one to finish you need to add it in anonymous method passed to setTimeout function. Otherwise your code will wait until previous is done
Example:
function callMe()
{
for(var i = 0; i < 100000; i++)
{
document.title = i;
}
}
var x = 10;
setTimeout(callMe, 0);
var el = document.getElementById('test-id');
el.innerHTML = 'Im done before callMe method';
That is the reason I use it.
Apart from previous answers I'd like to add another useful scenario I can think of: to "escape" from a try-catch block. A setTimeout-delay from within a try-catch block will be executed outside the block and any exception will propagate in the global scope instead.
Perhaps best example scenario: In today's JavaScript, with the more common use of so called Deferreds/Promises for asynchronous callbacks you are (often) actually running inside a try-catch.
Deferreds/Promises wrap the callback in a try-catch to be able to detect and propagate an exception as an error in the async-chain. This is all good for functions that need to be in the chain, but sooner or later you're "done" (i.e fetched all your ajax) and want to run plain non-async code where you Don't want exceptions to be "hidden" anymore.
AFAIK Dojo, Kris Kowal's Q, MochiKit and Google Closure lib use try-catch wrapping (Not jQuery though).
(On couple of odd occasions I've also used the technique to restart singleton-style code without causing recursion. I.e doing a teardown-restart in same loop).
To allow any previously set timeouts to execute.

Javascript setInverval seems slow?

So I am trying to do a setInterval that checks the placement of something on the page. Issue I am having is that if I set it for 10, 100, 250 it seems to be very slow and slows scrolling down.
setInterval('functionName()', 10);
setInterval('functionName()', 100);
setInterval('functionName()', 250);
UPDATE: The reason for the function is to move an element down the page when the user scrolls. The issue is that it is a Facebook app, in an iFrame, that is larger than the screen. I can't seem to find a way to attach the onScroll property outside of the iFrame, to Facebook (or maybe you can?!? I haven't had any luck yet) so I am being forced to use this method. Basically, it will grab the scroll height that Facebook passes in and move the element down the page. It works...but it seems to slow even scrolling down.
Is this something I just can't get around?
You're doing something every 10ms. That very well could intefere with the normal operation of the browser. The browser interface is blocked whenever javascript is running.
Perhaps if you describe what you're trying to do with the interval timers and post your code, we can suggest better performing ways to do that.
The minimum time resolution for setInterval() and setTimeout() varies by browser, and in some cases can be as much as 15 or 20 ms (some articles state up to 75ms). Your attempt to perform an action at higher resolutions (shorter intervals) is really more of a request to the browser -- there's no guarantee. Requests at resolutions higher than the browser's capability will be "clamped", and run no more frequently than that minimum. And of course, if the browser's workload is sufficiently high (as it is likely to be given the assurance of a continually called function), the interval may be significantly greater.
As a side note, it's best not to provide your function argument to setInterval() as a string. Doing so will cause that function be evaluated in the global scope. Instead of this:
setInterval('functionName()', 10);
you should use this:
setInterval(functionName, 10);
You should reconsider the need for running your function so frequently. Perhaps there's an event-driven alternative.
References: MDN on minimum delay
JavaScript is, by it's very nature, single threaded. That means that your JavaScript runs in the same process as your browser's UI.
So, whenever the browser is executing your JavaScript, it has to halt whatever it is that it's doing (which, quite often, might be drawing the page in the browser window), and run your code.
Since you are running a piece of code 100 times per second (1000 / 10), you are simply hindering your browsers normal form of operation!!
My guess is that functionName() is slow. 250 shouldn't be too bad for modern browsers. Post the function and we'll see if we can improve it.
Something that hasn't been mentioned: you're passing a string to setInterval when you really should be passing the function object itself:
setInterval(myFunction, 5000)
What happens when you give it a string like "functionName()" is that it's eval'ed, that might be the source of some of the slowness.

How does setTimeout work in Node.JS?

I guess that once it's executed it's on the queue, but in the queue is there any assurance it will invoke exactly after X milliseconds? Or will other heavy tasks higher on the queue delay it?
The semantics of setTimeout are roughly the same as in a web browser: the timeout arg is a minimum number of ms to wait before executing, not a guarantee. Furthermore, passing 0, a non-number, or a negative number, will cause it to wait a minimum number of ms. In Node, this is 1ms, but in browsers it can be as much as 50ms.
The reason for this is that there is no preemption of JavaScript by JavaScript. Consider this example:
setTimeout(function () {
console.log('boo')
}, 100)
var end = Date.now() + 5000
while (Date.now() < end) ;
console.log('imma let you finish but blocking the event loop is the best bug of all TIME')
The flow here is:
schedule the timeout for 100ms.
busywait for 5000ms.
return to the event loop. check for pending timers and execute.
If this was not the case, then you could have one bit of JavaScript "interrupt" another. We'd have to set up mutexes and semaphors and such, to prevent code like this from being extremely hard to reason about:
var a = 100;
setTimeout(function () {
a = 0;
}, 0);
var b = a; // 100 or 0?
The single-threadedness of Node's JavaScript execution makes it much simpler to work with than most other styles of concurrency. Of course, the trade-off is that it's possible for a badly-behaved part of the program to block the whole thing with an infinite loop.
Is this a better demon to battle than the complexity of preemption? That depends.
The idea of non-blocking is that the loop iterations are quick. So to iterate for each tick should take short enough a time that the setTimeout will be accurate to within reasonable precision (off by maybe <100 ms or so).
In theory though you're right. If I write an application and block the tick, then setTimeouts will be delayed. So to answer you're question, who can assure setTimeouts execute on time? You, by writing non-blocking code, can control the degree of accuracy up to almost any reasonable degree of accuracy.
As long as javascript is "single-threaded" in terms of code execution (excluding web-workers and the like), that will always happen. The single-threaded nature is a huge simplification in most cases, but requires the non-blocking idiom to be successful.
Try this code out either in your browser or in node, and you'll see that there is no guarantee of accuracy, on the contrary, the setTimeout will be very late:
var start = Date.now();
// expecting something close to 500
setTimeout(function(){ console.log(Date.now() - start); }, 500);
// fiddle with the number of iterations depending on how quick your machine is
for(var i=0; i<5000000; ++i){}
Unless the interpreter optimises the loop away (which it doesn't on chrome), you'll get something in the thousands. Remove the loop and you'll see it's 500 on the nose...
setTimeout is a kind of Thread, it holds a operation for a given time and execute.
setTimeout(function,time_in_mills);
in here the first argument should be a function type; as an example if you want to print your name after 3 seconds, your code should be something like below.
setTimeout(function(){console.log('your name')},3000);
Key point to remember is, what ever you want to do by using the setTimeout method, do it inside a function. If you want to call some other method by parsing some parameters, your code should look like below:
setTimeout(function(){yourOtherMethod(parameter);},3000);
The only way to ensure code is executed is to place your setTimeout logic in a different process.
Use the child process module to spawn a new node.js program that does your logic and pass data to that process through some kind of a stream (maybe tcp).
This way even if some long blocking code is running in your main process your child process has already started itself and placed a setTimeout in a new process and a new thread and will thus run when you expect it to.
Further complication are at a hardware level where you have more threads running then processes and thus context switching will cause (very minor) delays from your expected timing. This should be neglible and if it matters you need to seriously consider what your trying to do, why you need such accuracy and what kind of real time alternative hardware is available to do the job instead.
In general using child processes and running multiple node applications as separate processes together with a load balancer or shared data storage (like redis) is important for scaling your code.
setTimeout(callback,t) is used to run callback after at least t millisecond. The actual delay depends on many external factors like OS timer granularity and system load.
So, there is a possibility that it will be called slightly after the set time, but will never be called before.
A timer can't span more than 24.8 days.

Categories

Resources