Set minimum time and timeout - javascript

I have loading animation which displays while the webpage is loading in the background. Once loading is complete it disappears.
What I'd like...
1. The animation to appear for a minimum of 1 second.
2. Once the 1 second minimum has expired, the animation will be naturally removed following page loading.
3. To avoid the possibility of a fault (and watching an endless animation loop), I want the animation to time out if it takes more than 5 seconds to load.
Here's what I have so far...
$(window).load(function()
{
$('#followingBallsG').hide();
$('#backgroundcolor').hide();
});
Any assistance you can provide would be greatly appreciated. Thanks.

There are no built-in jQuery features for this. You will need to write out the logic for this. Here is a simple implementation, free of race-conditions.
(function(){
var didDone = false;
function done() {
//Prevent multiple done calls.
if(!didDone)
{
didDone = true;
//Loading completion functionality here.
$('#followingBallsG').hide();
$('#backgroundcolor').hide();
}
}
//Variables to keep track of state.
var loaded = false;
var minDone = false;
//The minimum timeout.
setTimeout(function(){
mindone = true;
//If loaded, fire the done callback.
if(loaded)
{
done();
}
}, 1000);
//The maximum timeout.
setTimeout(function(){
//Max timeout fire done.
done();
}, 5000);
//Bind the load listener.
$(window).load(function(){
loaded = true;
//If minimum timeout done, fire the done callback.
if(minDone)
{
done();
}
});
})();
I've wrapped it in a immediately invoked function expression and assumed $(window).load is the event you are listening for. It should be easy to adapt this to another event or to run at another time if this is not the desired effect.

Related

Using $.ajaxStop() to determine when page is finished loading in CasperJS

So far in my tests written in CasperJS, I've been using waitForSelector() on page-specific elements to determine if a page has fully loaded (including all the async ajax requests). I was hoping to come up with a more standard way of waiting for page load and was wondering if the following was possible?
Inject as clientscript the following (include.js)
$(document).ajaxStop(function() {
// Do something
})
Description of ajaxStop according to jquery api: Register a handler to be called when all Ajax requests have completed.
Define a casper.waitForLoad function that when called would wait for the "something" in above code block
Use the function in several parts of the test.
Also any tips on the // Do Something part would also be appreciated :) I was thinking about using the window.callPhantom feature in phantomJS but I'm reading that it's not officially supported in casperjs.
I would do something like this in include.js:
(function(){
window._allAjaxRequestsHaveStopped = false;
var interval;
$(document).ajaxStop(function() {
if (interval) {
clearInterval(interval);
interval = null;
}
interval = setTimeout(function(){
window._allAjaxRequestsHaveStopped = true;
}, 500);
});
$(document).ajaxStart(function() {
window._allAjaxRequestsHaveStopped = false;
if (interval) {
clearInterval(interval);
interval = null;
}
});
})();
This sets a (hopefully unique) variable to the window object that can be later retrieved. This also waits a little longer incase there is another request after the previous batch ended.
In CasperJS you would probably do something like the following to wait for the change in the request status. This uses adds a new function to the casper object and uses casper.waitFor() internally to check the change.
casper.waitForAjaxStop = function(then, onTimeout, timeout){
return this.waitFor(function(){
return this.evaluate(function(){
return window._allAjaxRequestsHaveStopped;
});
}, then, onTimeout, timeout);
};
And use it like this:
casper.start(url).waitForAjaxStop().then(function(){
// do something
}).run();
or this:
casper.start(url).thenClick(selector).waitForAjaxStop().then(function(){
// do something
}).run();

Why does the following JS function wreck the browser process?

var wait = function (milliseconds) {
var returnCondition = false;
window.setTimeout(function () { returnCondition = true; }, milliseconds);
while (!returnCondition) {};
};
I know there have been many posts already about why not to try to implement a wait() or sleep() function in Javascript. So this is not about making it usable for implementation purposes, but rather making it work for proof of concept's sake.
Trying
console.log("Starting...");wait(3000);console.log("...Done!");
freezes my browser. Why does wait() seemingly never end?
Edit: Thanks for the answers so far, I wasn't aware of the while loop never allowing for any other code to execute.
So would this work, then?
var wait = function (milliseconds) {
var returnCondition = false;
var setMyTimeOut = true;
while (!returnCondition) {
if (setMyTimeOut) {
window.setTimeout(function() { returnCondition = true; }, milliseconds);
setMyTimeOut = false;
}
};
return;
};
JavaScript is executed in a single thread. Only when an execution path exits can another execution path begin. Thus, when you launch your wait(3000), the following happens:
returnCondition is set to false
a timeout is scheduled
an infinite loop is started.
Each <script> tag, each event being handled, and each timeout (and also UI refresh, in case of a browser) initiate a separate execution path. Thus, a timeout of 3000 is not guaranteed to run in 3000ms, but at any time after 3000ms when the engine is "free".
The wait function never exits, so your script's execution path never ends, and the scheduled timeout's turn never comes.
EDIT:
That means, once a <script> tag has begun, or Node.js has started executing a JavaScript file, the execution has to reach the bottom before anything else can happen. If a function is started as a result of an event or a timeout, that function needs to exit before anything else can happen.
<script>
console.log("script top");
function theTimeout() {
console.log("timeout top");
// something long
console.log("timeout bottom");
}
setTimeout(theTimeout, 0);
setTimeout(theTimeout, 0);
console.log("script bottom");
</script>
There are three execution paths here. The first is the <script> tag's: it starts with printing "script top", schedules two timeouts (for "right now"), then prints "script bottom", and then the end of <script> is reached and the interpreter is idle. That means it has time to execute another execution path, and there are two timeouts is waiting, so it selects one of them and starts executing it. While it is executing, again nothing else can execute (even UI updates); the other timeout, even though it was also scheduled at "immediately", is left to wait till the first timeout's execution path ends. When it does, the second timeout's turn comes, and it gets executed as well.
JavaScript is single threaded. When you call setTimeout the method you passed in as an argument is placed to the async call stack. It means the very next line of code in your block is executing immediately after the setTimeout call and the function you passed in as an argument will execute after your wait method exits.
Your while loop is waiting for a condition which will never happen while the wait function is running because the function which will set your flag will not run until the wait function is done.
The correct way to implement wait is:
var wait = function (milliseconds, onEnd) {
window.setTimeout(function () { onEnd(); }, milliseconds);
};
wait(1000, function(){alert('hi')});
Here you pass in a callback function which will execute after the timeout.
If you have multiple async style calls you can use promises. Promises will make your code easy to read and it will be easy to chain multiple async calls together. There are very good promise librarians: JQuery has $.Deferred built into it but you can use Q if you are writing node.js code.
A promise style implementation would look something like this:
var wait = function (milliseconds) {
var onEnd = null;
window.setTimeout(function () { onEnd(); }, milliseconds);
return {
then: function(action){
onEnd = action;
}
}
};
wait(1000).then(function(){alert('hi')});
https://api.jquery.com/jquery.deferred/
https://github.com/kriskowal/q
The following book helped me a lot to understand this subject:
Async JavaScript: Build More Responsive Apps with Less Code by Trevor Burnham
https://pragprog.com/book/tbajs/async-javascript

Is javascript interval clear?

I'm stuck with such thing:
I have var calls update_interval, and I start/stop my intervals with it.
My problem is to understand if interval clear or not.
Smth like:
clearInterval(update_interval);
update_interval = false/null/undefined
is not counting due to the specific of my project.
Any ideas?
Theres is no built-in mechanism to check whether a timeout has completed or not. You will have to do it yourself, here is a minimal example:
var pending = true;
var timer = setTimeout(function() {
/* do some stuff */
pending = false;
}, 5000);
You can then check whether the timed function is done running or not:
if (pending) {
// hasn't run yet
}
else {
// is done running
}

Loading image while JavaScript function(s) run

is there a way to show a loading image while a JavaScript function is running. I have one that takes about 2-5 seconds, would be nice if i could have something like the jQuery-ajax function
$("#loading").bind("ajaxStart", function(){
$(this).attr("style", "visibility: visible")
}).bind("ajaxStop", function(){
$(this).attr("style", "visibility: hidden")
});
clarification edit:
The idea is that every time a JavaScript function runs and takes over, say 3/4 of a second, the loading image would be displayed. It really has nothing to do with this ajax function, just the same principle of always catching a running JavaScript and timing it.
Thanks!
Well then... After you commented, that changes everything.
You cannot have it automatically show when any javascript runs because there is no real hook for that. You can however leverage jquery custom events through the use of .trigger() and .bind() using your own custom event.
function myFunctionThatDoesSomething() {
$('body').trigger('Custom.BeginWork');
// Do Something ...
$('body').trigger('Custom.EndWork');
}
Although long running operations should probably be done asynchronously so they don't block on the event:
$("#Something").click(function() {
$('body').trigger('Custom.BeginWork');
setTimeout(function() { DoWorkFunction(/* you can pass params here if you need */); }, 0);
// Causes it to be executed in the background 0ms from now
});
function DoWorkFunction() {
// Stuff...
$('body').trigger('Custom.EndWork');
}
Then register a .bind() event much like .ajaxStart() and .ajaxStop()
$('#Working').bind('Custom.StartWork', function() {
$(this).show();
});
$('#Working').bind('Custom.EndWork', function() {
$(this).hide();
});
Here is a working jsFiddle Example.
Update:
In your jsFiddle you've done a double setTimeout. Here:
setTimeout(function() {
// Call Operation Here
try { setTimeout(function () { LongRunningOperation(10000); }, 1000);
}
finally
{
$("body").trigger('Custom.End');
}
}, 50); // 50ms delay because some browsers *cough*IE*cough* are slow at rendering dom changes
What this translates to is:
So the Custom.End event is getting fired after scheduling the long running function to run, not when it completes. setTimeout is asynchronous and non-blocking.

How to stop/override a Jquery TimeOut function?

I have a small jquery snippet that displays notification message at the top of the screen in response to user actions on a page. The notification is often displayed after Ajax actions with dynamic content inside it.
For example:
$("#mini-txt").html("Thank you!");
$("#mini").fadeIn("fast");
setTimeout(function() {$("#mini").animate({height: "hide", opacity: "hide"}, "medium");}, 3000);
The notification works well, except when a user does two or more actions in rapid succession, in which case the TimeOut function will confuse itself and the second message appears to come inside the previous 3000 milliseconds.
Is there a way to "kill" the previous notification if a new action is performed. I've got no problem with the actions/selectors, just the TimeOut function.... either stopping it or overriding it somehow. Or perhaps there's a better alternative for getting the message to linger on the screen for a few seconds before disappearing?
Thank you.
First, you store the return value for the setTimeout function:
// Set the timeout
var timeout = setTimeout(function()
{
// Your function here
}, 2000);
Then, when you're ready to kill the timeout...you just call clearTimeout with the stored value from the previous call to setTimeout.
// Then clearn the timeout
clearTimeout(timeout);
You can use .stop()
Stop the currently-running animation
on the matched elements.
jQuery 1.4 has a built in method to handle delays for animations you can do something like this:
$("#mini-txt").html("Thank you!");
$("#mini").fadeIn("fast").delay(3000).animate({height: "hide", opacity: "hide"}, "medium");
And then later when you want to clean the animation queue you can do:
$("#mini").stop(true);
This will clear timeout after function run with delay 500ms
var timeout = setTimeout(function(){
/* YOUR FUNCTION */
}, 500, function(){
clearTimeout(timeout);
});

Categories

Resources