Как сделать так, чтобы функция выполнялась только после того, как другая завершится?

Привет.

У меня есть две функции:
refreshAnchorSchema();
configUriAnchor();


Мне нужно, чтобы 2-ая гарантированно запустилась только после 1-ой. Я пробовал применить jquery new $.Deferred();, но не совсем понял как это сделать.

Спасибо.
  • Вопрос задан
  • 9941 просмотр
Решения вопроса 1
alexey-m-ukolov
@alexey-m-ukolov Куратор тега JavaScript
Дисклеймер
Кому не нравится название "обещания", мысленно заменяйте его на то, которое считаете подходящим. Я выбрал именно его, чтобы концепция, лежащая в их основе, была интуитивно понятна.

Если функция асинхронная, то лучше всего использовать обещания, что вы и попытались сделать (интерактивный пример).
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');
}


Есть еще один (очень, очень, очень плохой) вариант, основанный на таймерах и внешних флагах. Никогда так не делайте (код для системы из трех функций еще хуже).

Если внутри функций ничего асинхронного нет, то можно просто вызвать их друг за другом - следующая и так запустится после предыдущей (пример).
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы