2014-12-23 4 views
0

Я искал эту тему на SO больше часа и не смог найти такой случай, как мой.chaining javascript функции

У меня есть веб-приложение, которое я разработал на Ruby on Rails. Он основан на форме с несколькими полями и кнопками для выполнения действий.

Это примеры (мое реальное приложение использует больше функций и больше комбинаций действий): Когда поле1 изменено, я хочу выполнить функции JS function1(), затем function2(), затем function3(). Когда поле 2 изменено, я хочу выполнить функции JS function2(), затем function3(). Когда поле3 изменено, я хочу выполнить функцию функции JS3().

Все эти функции JS вызывают определенные действия, определенные в моем контроллере, и они обновляют форму с помощью AJAX. Мне бы хотелось, чтобы функция function2() начала выполняться только после того, как функция function1() завершила обновление формы, иначе результаты будут ошибочными.

Поскольку методы контроллера, вызываемые этими функциями, отправляют вызовы API на многие другие веб-сайты, такие как геокод Google или часовой пояс Google, время отклика непредсказуемо и может составлять от нескольких сотен до нескольких секунд.

Я попытался это:

onchange="function1();function2();function3()" 

, но это не сработало, потому что function2() начал выполняться до function1() завершил обновления через AJAX и тот же вопрос для FUNCTION3() в отношении function2 ().

Я также попытался:

onchange="function1();setTimeout(function(){function2();setTimeout(function(){function3()},FUNCTION2_DELAY)},FUNCTION1_DELAY)" 

, но это не сработало, потому что если FUNCTION1_DELAY установлен слишком долго, function2() не начнет выполняться до FUNCTION1_DELAY истек, в то время как function1() может выполняться намного быстрее, чем FUNCTION1_DELAY, и если значение FUNCTION1_DELAY установлено слишком короткое, функция2() начнет выполнение перед тем, как функция function1() завершит обновления, необходимые для выполнения функции2(). То же самое для функции 3() в отношении функции2().

Мой вопрос: есть ли более разумный способ сделать функцию2() начать выполнение только тогда, когда функция1() завершила обновление формы через AJAX, и то же самое для функции3() в отношении функции2()? Я знаю, что могу создавать новые методы контроллера, где я объединять эти функции, например слияние функций function1(), function2() и function3() в new_function1(), ... и т. Д., Но это делает мой код содержащим повторяющиеся действия и будет в конечном итоге сделать его сложнее поддерживать. Поэтому я предпочел бы более разумный способ справиться с этой проблемой.

+0

Возможный дубликат [Как мне вызвать 3 функции для их выполнения один за другим?] (http: // stackoverflow. ком/вопросы/5187968/как-должно-я вызову-3-функции-в-для-выполнения, их-один-а fter-the-other) – JRulle

+0

ajax является асинхронным. Вы не можете называть эти функции последовательно, не используя обещаний или используя обратные вызовы успешных последовательных запросов для вызова следующей функции. Возможно, вам стоит взглянуть на целые обещания ajax. Не видя своего кода, сложно помочь гораздо больше – charlietfl

+0

@JRulle: Спасибо за ваш ответ. Я посмотрел на это, и мой не дубликат, потому что ни один из примеров не использует AJAX. В моем случае, когда функция 1 завершила выполнение в браузере, все равно придется ждать обновления AJAX, прежде чем функция2 сможет выполнить правильно. Таким образом, завершение выполнения функции1 происходит не тогда, когда отправляется запрос AJAX, но он возвращается с сервера. Надеюсь, это прояснит различия. – rh4games

ответ

0

setTimeout асинхронный, так что не будет работать. Вы можете вызвать функцию 2 в конце функции 1, но все же внутри функции.Аналогично для функции 3:

function one(){ 
    ...logic... 
    function two(); 
} 

function two(){ 
    ...logic... 
    function three(); 
} 

function three(){ 
    ...logic... 
} 

В качестве альтернативы, вы можете создать какой-то очереди функций, и только перейти к следующему, когда ток один закончен:

var functionQueue = [ 
    one, 
    two, 
    three 
]; 

function next(){ 
    var nextFn = functionQueue.shift(); 
    if(nextFn){ 
    nextFn(); 
    } 
} 

function one(){ 
    ...logic... 
    next(); 
} 
// same for two & three 

Вы можете также использовать обещания, которые являются достаточно мощными и делают код более понятным для чтения, но могут быть чрезмерными для этой проблемы.