You're almost there - just missing an async
. But for the sake of completeness, here's a couple different strategies for running jQuery animations in sequence
Chain animate calls
.animate()
will automatically place animations in a queue for each element. This is set to true by default, but you can override by passing in the option { queue: false }
to force subsequent animations to fire immediately.
This example will animate marginLeft
first, then marginTop
after:
$("#a")
.animate({marginLeft: "40px"}, 1000)
.animate({marginTop: "40px"}, 1000)
<!-- begin snippet: js hide: true console: false babel: false -->
<!-- language: lang-js -->
$("#a")
.animate({marginLeft: "40px"}, 1000)
.animate({marginTop: "40px"}, 1000)
<!-- language: lang-html -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="a">Hello</div>
<!-- end snippet -->
Animate + Queue
As just observed, animations will automatically queue, but if you want to add your own methods to the queue, you can call .queue()
to add your own code. Just make sure to call the next()
param when you are done to start the next action in the queue.
This example will animate marginLeft
first, then change the text, then animate marginTop
:
$("#a")
.animate({marginLeft: "40px"}, 1000)
.queue(function(next) {
$(this).text("Hi");
next();
})
.animate({marginTop: "40px"}, 1000)
<!-- begin snippet: js hide: true console: false babel: false -->
<!-- language: lang-js -->
$("#a")
.animate({marginLeft: "40px"}, 1000)
.queue(function(next) {
$(this).text("Hi");
next();
})
.animate({marginTop: "40px"}, 1000)
<!-- language: lang-html -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="a">Hello</div>
<!-- end snippet -->
Promises + Async / Await
You can convert animations into a promise by calling .promise()
and then awaiting the promise.
Note: Just make sure to mark your function as async
since await is only valid in async function.
This example will animate marginLeft
first, then change the text, then animate marginTop
:
async function main() {
await $("#a").animate({marginLeft: "40px"}, 1000).promise()
$("#a").text("Hi");
await $("#a").animate({marginTop: "40px"}, 1000).promise()
}
main()
<!-- begin snippet: js hide: true console: false babel: false -->
<!-- language: lang-js -->
async function main() {
await $("#a").animate({marginLeft: "40px"}, 1000).promise()
$("#a").text("Hi");
await $("#a").animate({marginTop: "40px"}, 1000).promise()
}
main()
<!-- language: lang-html -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="a">Hello</div>
<!-- end snippet -->
jQuery.When()
You can combine multiple animations together by calling $.when
on multiple deferred elements to step them all at the same time. That returns a single promise that can be awaited or passed a callback.
This example will complete animations on both elements, then start the next animations:
$.when(
$("#a").animate({marginLeft: "40px"}, 1000),
$("#b").animate({marginLeft: "40px"}, 1000),
).then(()=>{
$("#a").animate({marginTop: "40px"}, 1000);
$("#b").animate({marginTop: "40px"}, 1000);
})
<!-- begin snippet: js hide: true console: false babel: false -->
<!-- language: lang-js -->
$.when(
$("#a").animate({marginLeft: "40px"}, 1000),
$("#b").animate({marginLeft: "40px"}, 1000),
).then(() => {
$("#a").animate({marginTop: "40px"}, 1000);
$("#b").animate({marginTop: "40px"}, 1000);
})
<!-- language: lang-html -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="a">Hello</div>
<div id="b">Goodbye</div>
<!-- end snippet -->
Further Reading