ДисклеймерКому не нравится название "обещания", мысленно заменяйте его на то, которое считаете подходящим. Я выбрал именно его, чтобы концепция, лежащая в их основе, была интуитивно понятна.
Если функция асинхронная, то лучше всего использовать
обещания, что вы и попытались сделать (
интерактивный пример).
one().done(two);
function one() {
var dfd = new $.Deferred();
// Запускаем асинхронную задачу. Например, ajax-запрос.
setTimeout(function () {
var foo = 'bar';
// "Выполняем обещание", передавая в него какую-то информацию.
// Передавать аргументы, разумеется, не обязательно.
dfd.resolve(foo);
}, 2000);
// Возвращаем из функции обещание, на которое могут подписаться другие функции.
// Обратите внимание, этот код выполнится до того, как завершится асинхронная задача.
return dfd.promise();
}
function two(foo) {
// Обрабатываем данные, полученные внутри асинхронной функции one.
console.log('two', foo);
}
Для трех функций расклад немного сложнее, но принцип
такой же.
Есть и более
элегантный способ запуска цепочки из трех функций:
кодone().then(two, onOneError).then(three, onTwoError);
function one() {
var dfd = new $.Deferred();
setTimeout(function () {
console.log('one');
if (Math.round(Math.random() * 10) >= 5)
{
dfd.resolve();
}
else
{
dfd.reject();
}
}, 1000);
return dfd.promise();
}
function two() {
var dfd = new $.Deferred();
setTimeout(function () {
console.log('two');
if (Math.round(Math.random() * 10) >= 5)
{
dfd.resolve();
}
else
{
dfd.reject();
}
}, 1000);
return dfd.promise();
}
function three() {
setTimeout(function () {
console.log('three');
}, 1000);
}
function onTwoError() {
console.log('twoError', arguments);
}
function onOneError() {
console.log('oneError', arguments);
}
Обратите внимание, что в этом примере показано, что обещания можно не только выполнять, но и отказываться от них и такие ситуации нужно обрабатывать отдельно.
Обещания - самый современный и удобный вариант, с ними код становится чище и понятнее. Единственная проблема, связанная с ними - это необходимость использовать сторонние библиотеки или полифилы, потому что обещания пока
поддерживаются далеко не во всех браузерах.
Другой вариант - передавать
callback, но это прямой путь в
callback hell. Для запуска трех и более функций подряд я его не рекомендую - смотрите сами, на что становится похож
код:
one(function () {
two(three)
});
function one(callback) {
console.log('one');
setTimeout(callback, 1000);
}
function two(callback) {
console.log('two');
setTimeout(callback, 1000);
}
function three() {
console.log('three');
}
Есть еще один (очень, очень, очень плохой)
вариант, основанный на таймерах и внешних флагах. Никогда так не делайте (
код для системы из трех функций еще хуже).
Если внутри функций ничего асинхронного нет, то можно просто вызвать их друг за другом - следующая и так запустится после предыдущей (
пример).