JavaScript time delay - javascript

I'm a newbie in this department, so I was wondering, can I make a type of if statement with a time delay? Example: if a certain action (maybe a click event) is done within a time period, the time is reset, and if it is not, a function is called.

You can't do this with an if statement, but you can with setTimeout and clearTimeout.
Here's an example of how you can make a function (a console.log statement) run every 2 seconds as long as you don't click the button. Clicking the button resets the timer so that another 2 seconds will need to pass before it begins logging again. You can adapt this to fit whatever actual work you need to happen.
var currentTimeoutId;
function resetTimeout() {
clearTimeout(currentTimeoutId);
currentTimeoutId = setTimeout(function() {
console.log('Too Late!');
resetTimeout();
}, 2000);
}
resetTimeout();
document.getElementById('demo').onclick = function() {
resetTimeout();
};
<button id="demo">Click Me Or Else I'll Log Something!</button>

Related

use setTimeout on a user interaction, but execute it only once

I have a button that is supposed to work in the following way:
When a user presses this button,setTimeout is called to wait a few seconds, and then execute a function.
Simplified, the code is as follows, were onButtonClick is called when the user presses the button:
function onButtonClick() {
// executes some trivial things
setTimeout(foo, 3000);
}
function foo() {
// do something
}
This works, however, the user is allowed (and even supposed to) click the button multiple times. Unintendedly, foo will, after waiting 3 seconds, be executed multiple times. Instead, I only wish foo to be executed 3 seconds after the last button click.
How can I achieve this behavior?
Use clearTimeout to cancel setTimeout.
That way whenever the user click the button again, the last timeout is canceled and the new timeout begins.
let timeout;
function onButtonClick() {
// executes some trivial things
clearTimeout(timeout);
timeout = setTimeout(foo, 3000);
}
function foo() {
console.log('foo');
}
<button onclick="onButtonClick()">click me</button>

Javascript: Start setTimeout() only if it hasn't been set already

I have a vibrate function that I want to execute every 3 seconds or so until a button is clicked
My way of trying to do this is by having a loop that executes until a condition is false, when the button is clicked, the condition gets set to false. I could use sleep inside my while loop, followed by a call to vibrate, except that I would like to break as soon as the button is clicked, and not have to wait 3 seconds or so.
I am trying to set a timeOut if the device is still vibrating, but I don't want to continually set timeouts, I only want one timeout set at a time, so that a timeout is only set if one is not set already
this.vibrate()
while(this.state.isVibrating){
if (timeout has not been set){
setTimeout(this.vibrate(), 3000)
}
}
clearTimeout()
It sounds like setInterval is a better option here.
let interval;
this.vibrate();
interval = setInterval(this.vibrate.bind(this), 3000);
Then you can have a function execute when the button is clicked that can clear the interval:
function buttonClicked() {
clearInterval(interval);
}
Just make sure the interval var is in the scope of the buttonClicked function.

Javascript mouseover run function, then wait and run again

I am trying to get a function to fire on mouseover of an element. However, if the function is already running I want it to not fire.
I have this for the mouseover trigger
onmouseover="runFunc()">
and I have this for the js:
var timerStarted = false;
function waitToStart() {
timerStarted = false;
}
function runFunc() {
if (!timerStarted) {
console.log('run function');
}
timerStarted = true;
setTimeout(waitToStart, 6000);
}
When I first hover over the element, I get
run function
and nothing happens for 6 seconds which seemed like it was working. However after 6 seconds the console output counted fast up to the amount of times I hovered over the function:
(24) run function
I'm struggling to understand why and how to make sure that the function only fires every 6 seconds after mouseover.
You're starting many timers. And eventually they all end and each set your boolean to false, even when in the half second before that you still started yet another timer.
What you really want is to either cancel any previously launched timer before issuing a new one, or to only launch a new one when you are sure the preceding one already timed out. The effect is a bit different: the first solution will reset the countdown with every mousemove (so must hold it still for at least 6 seconds), while the second will just make sure that there are at least 6 seconds between executions of the if block.
Here is how the second approach works:
var timerStarted = false;
function waitToStart() {
timerStarted = false;
}
function runFunc() {
if (!timerStarted) {
console.log('run function');
timerStarted = true; // <--- moved inside the IF block
setTimeout(waitToStart, 6000); //
}
}

Prevent and queue action (but only once globally) if previously called within X seconds

I always run into this problem and seem to implement a nasty looking solution.
It seems like a common design pattern to fire an action immediately, but not let that action queue up if clicked rapidly / delay firing if previously called within a timeframe. In my real world example, I have an AJAX call being made, so if I don't prevent repetitive actions the browser queues requests.
How would you implement this differently? What other options are there?
function myFunction() {
console.log("fired");
}
var timeout = null;
$("#foo").click(function() {
// if not previously clicked within 1 second, fire immediately
if (!timeout) {
myFunction();
timeout = setTimeout(function() {
timeout = null;
}, 1000);
} else {
// clicked again within 1s
clearTimeout(timeout); // clear it - we can't have multiple timeouts
timeout = setTimeout(function() {
myFunction();
timeout = null;
}, 1000);
};
});
With your current code, if you repeatedly click "#foo" at an interval slightly less than one second, say every 800ms, on first click it will fire the function immediately (obviously), but then it will fire the function exactly once more one second after the last click. That is, if you click ten times at 800ms intervals the function will fire once immediately and a second time approximately 8 seconds (800ms * 9 + 1000ms) after the first click.
I think you're better off removing the else case altogether, so that on click it will fire the function if it has not been called within the last second, otherwise it will do nothing with no attempt to queue another call up for later. Not only does that seem to me like a more logical way to operate, it halves the size of your function...
On the other hand, since you mentioned Ajax, rather than disabling the function based on a timer you may like to disable the function until the last Ajax request returns, i.e., use a flag similar to your timerid and reset it within an Ajax complete callback (noting that Ajax complete callbacks get called after success or failure of the request).
In the case of an auto-complete or auto-search function, where you want to send an Ajax request as the user types, you might want to remove the if case from your existing code and keep the else case, because for auto-complete you likely want to wait until after the user stops typing before sending the request - for that purpose I'd probably go with a shorter delay though, say 400 or 500ms.
Regarding general structure of the code, if I wanted a function to be fired a maximum of once per second I'd likely put that control into the function itself rather than in a click handler:
var myFunction = function() {
var timerid = null;
return function() {
if (timerid) return;
timerid = setTimeout(function(){ timerid=null; }, 1000);
// actual work of the function to be done here
console.log("myFunction fired");
};
}();
$("#foo").click(function() {
myFunction();
});
The immediately invoked anonymous function that I've added makes it uglier, but it keeps the timerid variable out of the global scope. If you don't like that obviously you could simply declare timerid in the same scope as myFunction() as you currently do.
This answer is getting kind of long, but if you have a lot of different functions that all need some kind of repeat control in them you could implement a single function to handle that part of it:
function limitRepeats(fn, delay) {
var timerid = null;
return function() {
if (timerid) return;
timerid = setTimeout(function(){ timerid = null; }, delay);
fn();
};
}
// myFunction1 can only be called once every 1000ms
var myFunction1 = limitRepeats(function() {
console.log("fired myFunction1()");
}, 1000);
// myFunction2 can only be called once every 3000ms
var myFunction2 = limitRepeats(function() {
console.log("fired myFunction2()");
}, 3000);
$("#foo").click(function() {
myFunction1();
myFunction2();
});

Javascript - Stop a repeating function [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How to pause a setTimeout call ?
I have a function that gets called on page load which starts off a repeating function:
setTimeout(function () {
repeat();
}, 8000)
This function calls repeat() every 8 seconds, inside this function I have a bit of ajax which updates a counter on the page. Clicking on the counter gives the user a drop down menu with a number of messages. The counter value equals the number of messages the user has. Kind of like Facebook notifications.
When clicking the drop down menu Im using jQuery to hide and show it:
$('#messages').click(function () {
$('#messagesDropDown').slideDown();
})
.mouseleave(function () {
$('#messagesDropDown').slideUp();
});
When the #messagesDropDown is visible I want to stop the repeat() function, to prevent the list of messages from updating while Im viewing the current ones.
On .mouseleave I want to start the repeat() function again.
Anyone have any ideas how I can 'STOP' a repeating function In the .click function and start it again on .mouseleave ?
setTimeout returns a ID of the timeout. You can store that value, and then use clearTimeout to stop the timeout when you want.
var timeout;
$('#messages').click(function () {
$('#messagesDropDown').slideDown(function () {
clearTimeout(timeout); // Cancel the timeout when the slideDown has completed.
});
})
.mouseleave(function () {
$('#messagesDropDown').slideUp();
clearTimeout(timeout); // Cancel incase it's still running (you can also set `timeout` to undefined when you cancel with clearTimeout, and apply some logic here (`if (timeout == undefined)` so you can leave it running rather than restarting it)
timeout = setTimeout(repeat, 8000); // Store the ID of the timeout
});
setTimeout will not set a recurring event; it will only fire once (like a delayed event). Look at setInterval (and clearInterval) instead.
You said that this code starts a repeating function:
setTimeout(function () {
repeat();
}, 8000)
Since setTimeout doesn't repeat, I assume that the repeat function itself fires off another setTimeout to call itself again after it runs (chained setTimeout calls).
If so, you have two options:
Have a control variable telling repeat whether to do its work or not. A simple boolean will do. Set the boolean when you want repeat to skip its work, and have repeat check it. This is the dead simple answer.
Have control functions for repeat, like so:
var repeatHandle = 0;
function startRepeat() {
if (!repeatHandle) {
repeatHandle = setTimeout(repeatTick, 8000);
}
}
function repeatTick() {
repeatHandle = 0;
repeat();
}
function stopRepeat() {
if (repeatHandle) {
clearTimeout(repeatHandle);
repeatHandle = 0;
}
}
...and then use them to control the repeats. Be sure to modify repeat to call startRepeat to schedule its next call rather than calling setTimeout directly.

Categories