I know that most probably such question has been requested several times but I have a need to show a popup or message or whatelse when a javascript function is triggered and hide it at the end.
See this simple js fiddle
That's the HTML code:
<div id='message'>Default message</div>
<input type='button' onclick='Run();' value='start'>
the div 'message' has to contain a simple text like "running" or "please wait" or ...
That's the JS function that took (delay) 3 seconds:
function Run() {
var delay = 3000; //-- 3 seconds
$( '#message' ).text('Please wait ' + delay + ' seconds...');
var start = new Date().getTime();
while (true) {
current = new Date().getTime();
if ( (start + delay) < current) {
break;
}
}
$( '#message' ).text('Done');
}
The expected behaviour is that the '#message' div contains "Please wait 3 seconds..." before to enter in the loop and "Done" string only at the end.
But that's not.
Can anyone explain me (most probably "again") why or suggest a link where to find an answer?
The JS event loop is too busy running while (true) {} to handle a DOM repaint.
Use setInterval, setTimeout, or requestAnimationFrame to trigger the next test of the time instead of a loop.
function Run() {
var delay = 3000; //-- 3 seconds
$( '#message' ).text('Please wait ' + delay + ' seconds...');
var start = new Date().getTime();
setTimeout(whenDelayIsOver, 50);
function whenDelayIsOver() {
if ( (start + delay) < current) {
$( '#message' ).text('Done');
} else {
setTimeout(whenDelayIsOver, 50);
}
}
}
… or just use setTimeout in the first place.
function Run() {
var delay = 3000; //-- 3 seconds
$( '#message' ).text('Please wait ' + delay + ' seconds...');
setTimeout(whenDelayIsOver, delay);
function whenDelayIsOver() {
$( '#message' ).text('Done');
}
}
Try this http://jsfiddle.net/aamir/23ZFY/11/
function Run() {
var secs = 3;
$('#message').text('Please wait '+ secs +' seconds...');
var timer = setInterval(function () {
if (secs == 1) {
clearTimeout(timer);
$('#message').text('Done');
return;
}
secs--;
$('#message').text('Please wait ' + secs + ' seconds...');
}, 1000);
}
The browser's display is only updated when the function completely finishes running.
You can run the second lot of code asynchronously by using setTimeout.
function Run() {
$('#message').text('Please wait 3 seconds...');
setTimeout(
function () {
var start = new Date().getTime();
while (true) {
current = new Date().getTime();
if ((start + 3000) < current) {
break;
}
}
$('#message').text('Done');
},0);
}
You have a very tight loop (while(true)...) which doesn't allow the UI to update at all. What you can do instead is this:
function Run() {
var delay = 3000; //-- 3 seconds
$('#message').text('Please wait ' + (delay/1000) + ' seconds...');
setTimeout(function () {
$('#message').text('Done');
}, delay);
}
Basically, set the "wait message" initially and use the setTimeout function to update the message again after 3 seconds.
Updated fiddle.
Related
could you please help me how to fix this? I want to send just one command, but to be as accurate as possible (on milliseconds).
This is the part I need to fix:
document.getElementById("arrTime").onclick = function () {
clearInterval(attInterval);
let time = document.getElementsByClassName("relative_time")[0].textContent.slice(-8);
input = prompt("Set Arrival Time", time);
inputMs = parseInt(prompt("Set the milliseconds", "500"));
delay = parseInt(delayTime) + parseInt(inputMs);
let arrivalTime;
arrInterval = setInterval(function () {
arrivalTime = document.getElementsByClassName("relative_time")[0].textContent;
if (arrivalTime.slice(-8) >= input) {
setTimeout(function () { document.getElementById("troop_confirm_submit").click(); }, delay);
}
}, 5);
document.getElementById("showArrTime").innerHTML = input + ":" + inputMs.toString().padStart(3, "0");
document.getElementById("showSendTime").innerHTML = "";
};
Now, there is an "if statement" to perform action at arrivalTime.slice(-8) >= input (so for example 19:24:30), but it is sending requests every 5ms. So over that one second time, it sends 200 requests to the server.
I don´t want to change those 5ms, as I need to have it as accurate as possible, but I want to break the script, freeze it or sleep it for 1 second once the command is performed. So something like: setTimeout(function () { document.getElementById("troop_confirm_submit").click(); Sleep 1 second }, delay);
Anyone who can help, please?
I'd advise to break up the functions as to manage the interval a little easier
document.getElementById("arrTime").onclick = function() {
clearInterval(attInterval);
let time = document.getElementsByClassName("relative_time")[0].textContent.slice(-8);
input = prompt("Set Arrival Time", time);
inputMs = parseInt(prompt("Set the milliseconds", "500"));
delay = parseInt(delayTime) + parseInt(inputMs);
startInterval(input, delay)
document.getElementById("showArrTime").innerHTML = input + ":" + inputMs.toString().padStart(3, "0");
document.getElementById("showSendTime").innerHTML = "";
};
function startInterval(input, delay) {
arrInterval = setInterval(function() {
let arrivalTime = document.querySelector(".relative_time").innerText;
if (+arrivalTime.slice(-8) >= +input) {
clearInterval(arrInterval); // pause the interval
setTimeout(() => {
startInterval(input, delay)
}, 1000 * 60); // restart the interval in 1 minute
setTimeout(() => {
document.querySelector("#troop_confirm_submit").click();
}, delay);
}
}, 5);
}
I want to ping a server for response every 3 seconds for the first 6 seconds, after that I want to increase the interval time to 5 seconds till i get the response. I did the first part, I'm trying to solve the next 5 seconds ping
var firstPing = 3000,
pingStop = 6000,
pingForever = 5000;
var ping = setInterval(function() { execute() }, firstPing);
setTimeout(function() {clearInterval(ping)}, pingStop);
setInterval(function() {execute()}, pingForever);
function execute() {
console.log('hello: ' + new Date().getSeconds());
// After successful response, clearInterval();
}
Might it be simpler to just call execute() every 1 second and only have execute do something when an incrementing counter variable is a certain value?
var ping = setInterval(function() { execute() }, 1000);
let v = 0;
function execute() {
v++;
if(v==3 || v==6 || (v>6 && v%5 == 1))
console.log('hello: ' + new Date().getSeconds());
// After successful response, clearInterval();
`
Here is something that manages the transition of the ping from 3 to 5 secs.
const firstPing = 3000,
pingStop = 6000,
pingForever = 5000;
let currentPing = 0;
let ping = setInterval(function() { execute() }, firstPing);
function execute() {
console.log('hello: ' + new Date().getSeconds());
// After successful response, clearInterval();
if(++currentPing >= 2 ) {
clearInterval(ping);
ping = setInterval(() => execute(), pingForever);
}
}
You can use count variable, you have firstPing of 3sec. Instead of clearing the interval you can update the firstPing with pingForever.
var firstPing = 3000,
pingStop = 6000,
pingForever = 5000;
let count = 0;
var ping = setInterval(() => {
execute();
firstPing = (count === 2) ? pingForever : firstPing;
count++;
console.log(count, firstPing);
}, firstPing);
function execute() {
// console.log('hello: ' + new Date().getSeconds());
}
I would just use setTimeout for simplicity.
var found = null;
function tryRequest() {
if (found) return;
// send request
// in successful response, set 'found' to 'true'
setTimeout(tryRequest, found == null ? 3000 : 5000);
found = false;
}
setTimeout(tryRequest, 3000);
I have a piece of code with while loop which I would like to stop by setTimeout(). But it seems like a endless loop, which never triggers setTimeout(). If I remove while loop, timeout triggers correctly. What is wrong please?
$(document).ready(function()
{
var i = 0, s = false;
setTimeout( function()
{
s = true;
console.log( "Timeuot!!!" );
console.log( "s value is " + s );
}, 1000 );
while( s === false )
{
console.log( "this is while and s is " + s );
i++;
}
console.log( "iterations: " + i );
});
JavaScript runs a single event loop. It won't stop in the middle of a function to see if there are any events (such as clicks or timeouts) that would trigger a different function.
In short: It won't run the timed function until the while loop has finished.
To do this sort of thing, you'd normally have an event driven iterator.
var i = 0,
s = false;
setTimeout(function() {
s = true;
console.log("Timeuot!!!");
console.log("s value is " + s);
}, 1000);
next();
function next() {
if (s) {
return done();
}
console.log({
s, i
});
i++;
setTimeout(next, 0);
}
function done() {
console.log("iterations: " + i);
}
As already mentioned the while loop blocks the one and only thread. To let your example do the thing you want, replace the while loop with setInterval(function) like this:
$(document).ready(function()
{
var i = 0, s = false;
setTimeout( function()
{
s = true;
console.log( "Timeout!!!" );
console.log( "s value is " + s );
}, 1000 );
var interval = setInterval(function() {
console.log( "this is while and s is " + s );
i++;
if (s) {
clearInterval(interval);
console.log("i is " + i)
}
}, 100);
});
setTimeout is never called do the the fact that the while never ends and so the even dispatcher is not going to trigger the setTimeout.
I'm working on a little "web app" for a quiz.
Each slide has got a certain amount of time to be answered (or 0 to infinite time).
I find JS here to do the countdown:
function Countdown(options) {
var timer,
instance = this,
seconds = options.seconds || 10,
updateStatus = options.onUpdateStatus || function () {},
counterEnd = options.onCounterEnd || function () {};
function decrementCounter() {
updateStatus(seconds);
if (seconds === 0) {
counterEnd();
instance.stop();
}
seconds--;
}
this.start = function () {
clearInterval(timer);
timer = 0;
seconds = options.seconds;
timer = setInterval(decrementCounter, 1000);
};
this.stop = function () {
clearInterval(timer);
};
}
var myCounter = new Countdown({
seconds: timetogo, // number of seconds to count down
onUpdateStatus: function (sec) {
elapsed = timetogo - sec;
$('.progress-bar').width(((elapsed / timetogo) * 100) + "%");
}, // callback for each second
onCounterEnd: function () {
//alert('counter ended!');
} // final action
});
myCounter.start();
I made a jsfiddle here :
https://jsfiddle.net/mitchum/kz2400cc/2/
But i am having trouble when you go to the next slide, the progress bar "bump".
after looking into "live source panel from chrome" I saw it's like the first "counter" is not stopped and still runs.
Do you have any tips or hint to help me to solve my bug ?
Thanks
You must pay attention to the scope of the variables. I change the "var myCounter" under document ready in "var myCounterFirst". Check the updated JSFiddle.
var timetogoFirst = $('.current').attr("data-time");
var myCounterFirst = new Countdown({
seconds: timetogoFirst, // number of seconds to count down
onUpdateStatus: function (sec) {
elapsed = timetogoFirst - sec;
$('.progress-bar').width(((elapsed / timetogoFirst) * 100) + "%");
}, // callback for each second
onCounterEnd: function () {
alert('counter ended!');
} // final action
});
myCounterFirst.start();
so i'm new to javascript and jquery. Need some help on how to run the 2nd function after the 1st one has completed?
The first function is a progress bar and the second one is a form that i want to fade in after the progressbar animation completed.
The script:
$(function() {
var msecsPerUpdate = 1000 / 60; // # of milliseconds between updates, this gives 60fps
var progress = $('progress');
var duration = 1; // secs to animate for
var interval = progress.attr('max') / (duration * 1000 / msecsPerUpdate);
var animator = function() {
progress.val(progress.val() + interval);
if (progress.val() + interval < progress.attr('max')) {
setTimeout(animator, msecsPerUpdate);
} else {
progress.val(progress.attr('max'));
}
}
$('a#forgot').click(animator);
});
$(function(e) {
e.preventDefault();
$('generator#forgot').css('bottom', '5px');
$(this).fadeOut('medium', function() {
$('a#back').fadeIn();
});
});
Thanks in advance!
I'd add a callback function to your animator function to make it look like this:
var animator = function(callback) {
progress.val(progress.val() + interval);
if (progress.val() + interval < progress.attr('max')) {
setTimeout(animator, msecsPerUpdate);
} else {
progress.val(progress.attr('max'));
callback();
}
}
Then you can call it like this:
$('a#forgot').click(function() {
animator(function() {
console.log('this runs after your animation has completed');
});
});
Note: this is a simplified code-snippet without params or error handling, which you might wanna add.