var intervalHandle ;
var currentOpacity=0;
function beginAnimate() {
current_question_div = document.getElementById(current_question);
intervalHandle = setInterval(function(){
animateBox(current_question_div)
}, 200);
alert("Hellow ashik !");
}
function animateBox(current_question_div) {
current_question_div.style.backgroundColor = "lightblue";
currentOpacity = currentOpacity + .091;
current_question_div.style.opacity = currentOpacity;
if(currentOpacity > 1) {
alert("END");
clearInterval(intervalHandle);
}
}
<P onclick="beginAnimate">Click</p>
Everything is ok, but alert("Hellow ashik !"); working while interval is in execution. I want to open the alert("Hellow ashik !") When the clearInterval occurred. Means now other JavaScript code is executing in parallel while interval is also executing. I need to execute only one thread at a time. Please help. Is there a way to execute this code one by one. Thanks.
This code should accomplish what you want:
var intervalHandle,
currentOpacity = 0;
function beginAnimate()
{
current_question_div=document.getElementById(current_question);
/* call any other functions that need to run before the animation starts here */
alert("Hellow ashik !");
intervalHandle = setInterval(function(){
// note 'endAnimate()' is passed to the 'animateBox()' function as a callback
animateBox(current_question_div, endAnimate)
}, 200);
/* call any functions that can run while the animation is running here */
}
function endAnimate() {
alert("The end!");
/* call any other functions that need to be run after the animation here */
}
function animateBox(current_question_div, callback) {
current_question_div.style.backgroundColor = "lightblue";
currentOpacity = currentOpacity + .091;
current_question_div.style.opacity = currentOpacity;
if(currentOpacity>1)
{
alert("END");
clearInterval(intervalHandle);
if (callback && typeof(callback) === 'function') {
callback();
}
}
}
<P onclick="beginAnimate">Click</p>
JavaScript is a single threaded language -- ignoring WebWorkers or other workarounds. However, it is asynchronous and because of that you often see behavior that looks like threading. One way to work around these issues is to use the callback pattern.
In the callback pattern, you pass a function to be called later when your asynchronous function completes. JavaScript makes this simple as functions are first class objects and can be passed or assigned to just as easily as a number.
In a browser, javaScript has a single-threaded nature, thus it executes on a single thread per window. This means that the execution diagram is one dimensional: javaScript can only ever execute one piece of code at a time.
The browsers are event-driven. Most events are asynchronous, such as mouse clicks, key press, and timers. They are only run when there is an opening in the execution; and in the meantime, they are forced to get into the event queue waiting for execution.
<p id="test"></p>
document.getElementById("test").innerHTML += "a";
var intervalHandle = setInterval(function(){
callback();
}, 200);
document.getElementById("test").innerHTML += "c";
function callback() {
document.getElementById("test").innerHTML += "b";
//here where should be located all the code supposed to be executed after the timeinterval.
clearInterval(intervalHandle);
//here where should be located all the code supposed to be executed after the clearInterval.
}
Check this link jsfiddle to see the working example.
In the example above, the javascript thread starts setting the content of p to "a", then delays the execution of callback. This goes to the Event queue on the nearest timer tick after 200ms. And then continue execution, setting the content of p to "c".
So if you want to execute something after the clearInterval, then you should place it after the clearInterval.
Hope it's useful!
Related
I have a script that changes some values and clicks some buttons in a browser. I'm looking for a way to pause the execution of the code for x seconds without making the browser lag out. I'm using Firefox and I paste this script into its console. I'm aware of the setTimeout() function. However, this function doesn't stop executing the code, but rather waits x seconds till executing it. I'm looking for a complete solution that's similar to Python's time.sleep() function and pauses the execution of the code completely.
var init = 0.01
var start = init
var $odds = $("#oddsOverUnder")
var $button = $("#roll")
var $bet = $("#bet")
function roll(){
$bet.val(start)
$button.click()
//i want to pause the execution of the code here//
$button.click()
//and here//
refreshIntervalId=setInterval(roll2, 2000)}
function roll2(){
var tr = document.querySelector("#myBetsTable tr:nth-child(2)")
var cls = tr.getAttribute('class')
if (cls === 'success'){
start = init
$bet.val(start)}
else{
start = start * 2
$bet.val(start)
$odds.click()}
clearInterval(refreshIntervalId)
roll()}
roll()
There's no equivalent to Python's time.sleep() in JavaScript, which generally executes asynchronously by design. If you'd like to delay execution of code, you can use setTimeout, as you mentioned.
Without understanding exactly what your code is supposed to do, I can't suggest the ideal architecture for this problem. There's definitely a better way to do it than what I'm about to suggest. Still, to answer your question, you can simulate what you're asking this way:
function roll() {
$bet.val(start);
$button.click();
setTimeout(function () {
$button.click();
setTimeout(function () {
refreshIntervalId = setInterval(roll2, 2000);
}, 1000);
}, 1000);
}
How about setting timeouts inside a timeout?
function roll() {
$bet.val(start)
$button.click()
setTimeout(function() {
$button.click();
setTimeout(
function() {
$button.click();
refreshIntervalId = setInterval(roll2, 2000)
},
5000
);
},
5000
);
}
also, please see: https://stackoverflow.com/a/951057/2119863
I have this code:
function toStop(){
while(true){}
}
toStop();
Now, how can I stop this? Or how can I kill the current thread if this function call is somewhere in the setInterval running thread? Example:
var id = setInterval(function(){
toStop();
}, 1000);
//stop thread/timer with id here.
clearInterval doesn't work because it waits until the function call ends.
Thanks!
"Can I stop the execution of a function from outside that function?"
No, you can't programmatically.
JavaScript is single-threaded and if you run a piece of code that makes it infinitely busy, such as while(true);, then nothing else will ever be able to execute.
Calling such a piece of code within setTimeout or setInterval will have the same result, since the callback of these gets executed in the only thread we have as well.
However, you can create a timed recurring execution using setInterval or setTimeout, which can be stopped.
var timerId = setInterval(function () {
//Process an iteration of the loop in here
//If you cause an infinite loop in here, you will have the same issue
}, 50);
//stop the timer after ~3 seconds
setTimeout(clearInterval.bind(null, timerId), 3000);
Notes:
4 is the lowest interval that could be honored as specified in the SPEC.
setInterval will stack if the callback takes more time to execute than the specified interval. For that reason I never use setInterval and always use setTimeout.
Timer intervals are not guaranteed to be accurate
e.g. with setTimeout
var stopProcessing = startProcessing();
//Stop processing after ~3 seconds
setTimeout(stopProcessing, 3000);
function startProcessing() {
var timerId;
!function process() {
//Do some processing
//Continue processing in ~50 ms
timerId = setTimeout(process, 50);
}();
return function () { clearTimeout(timerId); }
}
Instead of an infinite loop, just use an if statement and wrap it in an interval:
var shouldContinue = true;
var interval = 0;
function toStop() {
if (interval == 0) {
interval = setInterval(function() {
if(shouldContinue) {
...
}
else {
clearInterval(interval);
interval = 0;
}
}, 200); // Or whatever interval makes sense
}
}
toStop();
// ...
shouldContinue = false;
See this principle in action here.
No, you can't programmatically, as #plalx said but you could try this: declaring a binding outside and check on that to continue or stop the loop:
let letMeGoOut;
function toStop(){
while(letMeGoOut != false)
}
toStop();
Here, I've created a function on mouseover that triggers a loop changing the opacity of the h1. It goes on till the mouse cursor moves out and is over something else in the page.
Here is the example: https://codepen.io/Mau-Di-Bert/pen/VqrRxE
I am trying to create the following functionality in my javascript:
$("mySelector").each(function(){
// Do something (e.g. change div class attribute)
// call to MyFunction(), the iteration will stop here as long as it will take for myFunction to complete
});
function myFunction()
{
// Do something for e.g. 5 seconds
}
My question is how can I stop every iteration for the duration of the myFunction()?
No, that isnt possible. You'll have to code it differently, possibly with a setTimeout based on the current index of .each.
$("mySelector").each(function(i){
// Do something (e.g. change div class attribute)
// call to MyFunction(), the iteration will stop here as long as it will take for myFunction to complete
setTimeout(myFunction,i*5000);
});
function myFunction()
{
// Do something for e.g. 5 seconds
}
Edit: You can also do it with queuing: http://jsfiddle.net/9Bm9p/6/
$(document).ready(function () {
var divs = $(".test");
var queue = $("<div />");
divs.each(function(){
var _this = this;
queue.queue(function(next) {
myFunction.call(_this,next);
});
});
});
function myFunction(next) {
// do stuff
$(this).doSomething();
// simulate asynchronous event
var self = this;
setTimeout(function(){
console.log(self.id);
// go to next item in the queue
next();
},2000);
}
Here's a jsFiddle that I think will do what you need:
http://jsfiddle.net/9Bm9p/2/
You would just need to replace the selector with what you use.
The "loop" that is occurring will wait for myFunction to finish before moving on to the next element. I added the setTimeout inside of myFunction to simulate it taking a period of time. If you are using asynchronous things, such as an AJAX request, you would need to put the call to myFunction inside of the complete method...or in the callback of an animation.
But as someone already commented, if everything in myFunction is synchronous, you should be able to use it as you are. If you are looking for this process to be asynchronous, or if things in myFunction are asynchronous, you cannot use a for loop or .each().
(function () {
"use strict";
var step = 0;
var content = $("mySelector");
var max = content.length;
var speed = 5000; // ms
var handle = setInterval(function () {
step++;
if (step >= max) {
clearInterval(handle);
} else {
var item = content[step];
// do something
}
}, speed);
}());
setInterval will do it once-every-n-miliseconds, and clearInterval will stop it when you're done. This won't lock up the browser (provided your "do something" also doesn't). FRAGILE: it assumes that the results of $("mySelector") are valid for the duration of the task. If that isn't the case then inside do something then validate item again.
I have a setInterval calling a loop which displays an animation.
When I clearInterval in response to a user input, there are possibly one or more loop callbacks in queue. If I put a function call directly after the clearInterval statement, the function call finishes first (printing something to screen), then a queued loop callback executes, erasing what I wanted to print.
See the code below.
function loop() {
// print something to screen
}
var timer = setInterval(loop(), 30);
canvas.onkeypress = function (event) {
clearInterval(timer);
// print something else to screen
}
What's the best way to handle this? Put a delay on the // print something else to screen? Doing the new printing within the loop?
Edit: Thanks for the answers. For future reference, my problem was that the event that triggered the extra printing was buried within the loop, so once this executed, control was handed back to the unfinished loop, which then overwrote it. Cheers.
You could also use a flag so as to ignore any queued functions:
var should;
function loop() {
if(!should) return; // ignore this loop iteration if said so
// print something to screen
}
should = true;
var timer = setInterval(loop, 30); // I guess you meant 'loop' without '()'
canvas.onkeypress = function (event) {
should = false; // announce that loop really should stop
clearInterval(timer);
// print something else to screen
}
First of all, you probably meant:
var timer = setInterval(loop, 30);
Secondly, are you sure calling clearInterval does not clean the queue of pending loop() calls? If this is the case, you can easily disable these calls by using some sort of guard:
var done = false;
function loop() {
if(!done) {
// print something to screen
}
}
var timer = setInterval(loop(), 30);
canvas.onkeypress = function (event) {
clearInterval(timer);
done = true;
// print something else to screen
}
99 times out of 100, this works perfectly:
function a(){
setInterval("b()",1000);
updateText("still working");
}
function b(){
timer++;
updateText(timer);
}
Occasionally the first loop waits for 20 seconds to 2 minutes. Thereafter it runs perfectly. I know the timer can pause on Android phones (when the soft keyboard is shown). Are there other conditions that might delay setInterval?
Firstly, it is strongly advised you provide a callback(function) as the first argument and not a string, because that string is evaluated in the global scope and we all know that bad things happen when we use eval in js (related eval post : When is JavaScript's eval() not evil?).
So, your
setInterval("b()", 1000);
should be rewritten as :
setInterval(b, 1000);
or:
setInterval(function() { b(); }, 1000);
I also recommend you use setTimeout to simulate a setInterval.
The main downfall of the setInterval function is that it executes a block of code every n milliseconds, regardless of the execution of the previous block of code.
So if for some reason a setInterval callback takes longer to execute than the delay provided, it will cause some stack overflows.
Let's take the following code for example :
function foo() {
// this takes about 2 seconds to execute
// .. code here
}
setInterval(foo, 1000);
This will actually freeze the browser because it will execute foo for an (almost) infinite number of times but it will never finish it.
The solution in this kind of case is to emulate the setInterval with setTimeout, in order to ensure that the callback has finished to execute before calling it again:
function foo() {
// this takes about 2 seconds to execute
// .. code here
}
function newSetInterval(callback, duration, callbackArguments) {
callback.apply(this, callbackArguments);
var args = arguments,
scope = this;
setTimeout(function() {
newSetInterval.apply(scope, args);
}, duration);
}
newSetInterval(foo, 1000);
Now, foo is called again only after the previous instance has finished the code execution.
I would apply the same thing to your code, in order to let the browser decide when it can execute the code, and not to force it to execute the block of code weather it's busy at that moment or not:
function a() {
newSetInterval(b, 1000);
updateText("still working");
}
function b() {
timer++;
updateText(timer);
}
function newSetInterval(callback, duration, callbackArguments) {
callback.apply(this, callbackArguments);
var args = arguments,
scope=this;
setTimeout(function() {
newSetInterval.apply(scope, args);
}, duration);
}
If you're interested, I've rewritten the setInterval and clearInterval functions in order to use them anywhere, without taking care of stack overflows :
function setInterval(f, time) {
setInterval.ids = setInterval.ids || {};
setInterval.idCount = setInterval.idCount || 0;
var that = this,
id = setInterval.idCount++,
// to prevent firefox bug that adds an extra element to the arguments
l = arguments.length - 2;
(function theFn() {
// to prevent firefox bug that adds an extra element to the arguments
var args = [].slice.call(arguments, 0, l);
f.apply(this, args);
setInterval.ids[id] = setTimeout.apply(this, [theFn, time].concat(args));
}).apply(that, [].slice.call(arguments, 2, arguments.length));
return id;
}
function clearInterval(id) {
if(!setInterval.ids || !setInterval.ids[id]) {
return false;
}
clearTimeout(setInterval.ids[id]);
return true;
}
try this,
setInterval(b, 1000);
or
setInterval(function(){
timer++;
updateText(timer);
}, 1000);