Running Asnychronous Functions in Sequence
This demo shows two ways to run asynchronous functions that use the jQuery Deferred API (like $.ajax or $.get requests) in sequence
by Patrick Hund
HTML
<div class="container">
<div class="row">
<div class="col-md-12">
<h2>Running Asnychronous Functions in Sequence</h2>
<h4>
This demo shows two ways to run asynchronous functions that use the
<a href="http://api.jquery.com/category/deferred-object/">jQuery Deferred API</a>
(like <a href="http://api.jquery.com/jQuery.ajax/">$.ajax</a> or
<a href="http://api.jquery.com/jQuery.get/">$.get</a> requests) in sequence:
</h4>
</div>
</div>
<div class="row">
<div class="col-md-6">
<p>The left button runs the functions by nesting the returned deferred objects with their <em>then</em> methods, like so:</p> <pre>
one().then(function () {
two().then(function () {
three().then(function () {
four();
});
});
});
</pre>
</div>
<div class="col-md-6">
<p>The right button runs the functions by using a helper function that executes them using recursion, like so:</p> <pre>
function invoke() {
var functions = arguments;
(function recursion(counter, deferred) {
if (counter === functions.length) {
return;
}
if (deferred) {
deferred.then(function () {
recursion(counter + 1, functions[counter]());
});
} else {
recursion(counter + 1, functions[counter]());
}
}(0));
}
invoke(one, two, three, four);
</pre>
</div>
</div>
<div class="row">
<div class="col-md-6">
<button id="nestedThens" type="button" class="btn btn-primary full-width">run with nested "then" methods</button>
</div>
<div class="col-md-6">
<button id="recursion" type="button" class="btn btn-primary full-width">run with recursion function</button>
</div>
...
CSS
.console {
background-color: #000000;
width: 100%;
height: 200px;
overflow: scroll;
padding: 10px;
border-radius: 4px;
}
.console p {
margin: 0;
color: green;
}
.console p.new {
color: lime;
}
.margin-top {
margin-top: 10px;
}
.margin-bottom {
margin-bottom: 10px;
}
.full-width {
width: 100%;
}
JavaScript
var one, two, three, four;
function log(msg) {
var $console = $("#console");
$console.find("p").last().removeClass("new");
$console.append("<p class=\"new\">" + msg + "</p>");
$console.scrollTop($console.prop("scrollHeight"));
}
function withDelay(func) {
var def = $.Deferred();
window.setTimeout(function () {
func();
def.resolve();
}, 1000);
return def;
}
function logWithDelayF(msg) {
return function () {
return withDelay(function () {
log(msg);
});
};
}
function invoke() {
var functions = arguments;
(function recursion(counter, deferred) {
if (counter === functions.length) {
return;
}
if (deferred) {
deferred.then(function () {
recursion(counter + 1, functions[counter]());
});
} else {
recursion(counter + 1, functions[counter]());
}
}(0));
}
one = logWithDelayF("function " + 1);
two = logWithDelayF("function " + 2);
three = logWithDelayF("function " + 3);
four = logWithDelayF("function " + 4);
function withNestedThens() {
log("running with nested thens...");
one().then(function () {
two().then(function () {
three().then(function () {
four();
});
});
});
}
function withRecursion() {
log("running with recursion function...");
invoke(one, two, three, four);
}
$("#nestedThens").click(withNestedThens);
$("#recursion").click(withRecursion);