I have a function foo
and I wanted to add a sleep/wait function to make a kind of DOM elements animation. I've already done some research and I know that it's impossible to pause a javascript function because it freezes browser - correct me if I'm wrong. How can I overcome it?
function foo() {
while (someCondition) {
var $someDiv = $('.someDiv:nth-child(' + guess + ')');
$someDiv.css({'background-color': 'red'});
wait 1000ms
$someDiv.css({'background-color': 'blue'});
wait 1000ms
if (someCondition2) {
doSomething; }
else {
for loop }
}
}
$someDiv
refers to different DOM element with each while
loop iteration because variable guess
changes
What I've tried
I used the function below and it worked but the problem is I couldn't use a for
loop in my async function foo
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
I tried setTimeout
but I wasn't able to achieve any valid result.
If I wrap in setTimeout
this piece of code:
('$someDiv').css({'background-color': 'red'});
then after specified amount of time all $someDiv's
change css style together (keep in mind that $someDiv
refers to different DOM element with each while
loop iteration).
If I wrap in setTimeout
a piece of code with if
, else
statements then I've got an error - Infinite Loop
Question
The foo function is simplified just for visualisation the problem. The original function I'm working on you can find on codepen (findNumber
function)
I want to make a binary search algorithm animation. Something similar to this
How can I achieve the desired result?
In general: How can I animate DOM elements in a loop with interval between each iteration?
The nicest, cleanest solution to this problem is with the async
/await
feature that will come in a future version of Javascript (ES2017). This allows you to get out of callback hell. You can create a simple sleep
function that looks like this:
function sleep(time) {
return new Promise(resolve => setTimeout(()=>resolve(), time));
}
You could use this with normal Promise
handling:
sleep(1000).then(()=>console.log('A second later'));
However, with the async
functionality you can use the await
keyword to make the code wait for the promise to be resolved before continuing.
async function doSomething() {
await sleep(1000);
console.log('A second later');
}
This means that you can use a normal loop as well, including break
and continue
statements:
async function doSomething() {
let i = 0;
while (true) {
await sleep(1000);
console.log(i);
if (++i === 5) break;
}
}
This means that your code can be dramatically simplified:
async function foo() {
var n = 5;
while (n > 0) {
n--;
var wait = 0;
//$('#someDiv').css({'background-color': 'red'});
console.log('doSomething-1');
//wait 1000ms
await sleep(1000);
//$('#someDiv').css({'background-color': 'blue'});
console.log('doSomething-2');
//wait 1000ms
await sleep(1000);
if (true) {
console.log('doSomething-3');
break;
} else {
console.log('loop')
}
}
}
(jsFiddle)
The only problem is that this functionality has far from universal support. You therefore need to transpile it using software like Babel.
Note also that, behind the scenes, your foo
function now returns immediately and gives a Promise
. That Promise
is resolved with the return value of the function. So if you wanted to do more code when foo
was completed, you would have to do foo().then(/*callback*/)
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With