I try to write a function that shakes/nudges a window popup
this.nudge = function() {
var stopped = false;
var x=10;
setTimeout(function() {
stopped = true;
},1000);
for (i=0;;i++){
if (stopped) break;
window.moveBy(0,x)
window.moveBy(x,0)
window.moveBy(0,-x)
window.moveBy(-x,0)
}
}
Problem is : it never stops !
I try to write a function that shakes/nudges a window popup
this.nudge = function() {
var stopped = false;
var x=10;
setTimeout(function() {
stopped = true;
},1000);
for (i=0;;i++){
if (stopped) break;
window.moveBy(0,x)
window.moveBy(x,0)
window.moveBy(0,-x)
window.moveBy(-x,0)
}
}
Problem is : it never stops !
Share Improve this question asked Jul 1, 2015 at 13:54 yarekyarek 12.1k31 gold badges130 silver badges248 bronze badges 2-
2
Of course - you never give it a chance to execute the
stopped = true
. Javascript (or to be more precise, the waysetTimeout
works in a browser) isn't multi-threaded. You're blocking the main thread with your cycle. This simply isn't how you're supposed to code effects in JS. – Luaan Commented Jul 1, 2015 at 13:55 - 1 You could use an interval instead and 'shake' the popup inside that interval. This way you can stop shaking the moment you remove the interval. Alternatively don't use a loop, move the 'shaking' code into its own function and have that function call itsself until stopped = true. – Shilly Commented Jul 1, 2015 at 14:00
3 Answers
Reset to default 11Since JavaScript is single-threaded (as @Luaan mentioned in the ments), your infinite loop will run infinitely and prevent any timeouts or other events from being executed. The runtime won't even try to preempt your loop (break it in the middle to run other code) and will wait until your main function has returned -- which never happens.
You cannot use a busy wait or other, similar loops in JS: they prevent the browser's UI from responding and will cause any events to be deferred until execution has finished and the script thread is free.
To process your loop correctly in an event-friendly fashion, you can either set it up as a timeout every repetition or an interval, like:
this.nudge = function() {
var x = 10;
var loop = setInterval(function() {
window.moveBy(0,x)
window.moveBy(x,0)
window.moveBy(0,-x)
window.moveBy(-x,0)
}, 100);
setTimeout(function() {
clearInterval(loop);
}, 1000);
}
This simplifies your code by removing the stopped
variable and simply started/clearing a deferred loop when the timeout has expired. You can adjust the timing on either function to change the rate of animation and overall duration.
What do you think about such solution?
var i = 0;
(function a(timeout, startTime) {
console.log(i++);
if (Date.now() - startTime > timeout) return;
setTimeout(function() {
/* window.moveBy(0, x);
window.moveBy(x, 0);
window.moveBy(0, -x);
window.moveBy(-x, 0); */
a(timeout, startTime);
}, 0);
})(1000, Date.now());
Maybe you need something lie this :
this.nudge = function() {
var x=10;
var ts = Date.now();
while(Date.now()-ts<1000){
window.moveBy(0,x)
window.moveBy(x,0)
window.moveBy(0,-x)
window.moveBy(-x,0)
}
}