Предотвращение запуска функции, если параллельная функция уже завершилась с ошибкой (используя jQuery $.when())

У меня есть довольно запутанная серия асинхронных функций, которые я объединяю в цепочку с помощью jQuery Deferreds.

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

function makeOmelette() {
    $.when(
        crackEggs().then(beatEggs),
        washTomatos().then(chopTomatos)
    ).then(mixEggsAndTomatos).then(fryEggsAndTomatos).done(function() {
        msg('Omelette is ready!');
    }).fail(function() {
        msg('Oh no, omelette fail!');
    });
}

Обработчики done() и fail() в конце имеют дело с успехом или неудачей. Я хотел бы, чтобы обработчик fail() выполнялся, как только что-то пойдет не так, в любом месте цепочки, и чтобы все дальнейшее выполнение было остановлено.

В основном это работает - кроме одного случая. Если при взломе яиц произошел сбой, то помидоры все еще вымыты и нарезаны - даже если сбой уже произошел к тому времени, как началось выполнение одной из этих задач. Точно так же, если при мытье помидоров происходит сбой, это не мешает запуску функций crackEggs и beatEggs.

Вы можете увидеть пример здесь.

Меня беспокоит это то, что в моем реальном жизненном коде я не хочу, чтобы браузер выполнял AJAX-вызовы на сервер, что могло бы потенциально изменить состояние, если в этом нет никакого смысла, потому что общий процесс уже завершился неудачей.

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

Спасибо!

2 ответа

Решение

Добавить переменную в статусы. например, внутри done( var status = 1 ) и внутри fail( var status = 2 затем поместите простое выражение перед запуском параллельной функции, чтобы она не запускалась, если status = 2,

Попробуй (этот паттерн)

HTML

<input type="button" value="reject" />
<input type="button" value="resolve" /> <output></output> <output></output>
<div id="messages"></div>

JS

$(function () {
    $("input").on("click", function (e) {
        var dfd = new $.Deferred();

        $("#messages").children().remove();
        makeOmelette(this.value);

        function makeOmelette(resolveReject, dfd) {
            // dfd = dfd;
            $.when(
            // `crackEggs("resolve")`, `crackEggs("reject")`
            crackEggs(resolveReject), 
            washTomatos())
                .done(function (a, b) {
                if (a === "rejected") {
                    err();
                };
                if (a === "resolved") {
                    beatEggs();
                    chopTomatos();
                    mixEggsAndTomatos();
                    fryEggsAndTomatos();
                    success();
                };

            });
        };

        function success() {
            dfd.done(function (s) {
                msg('Omelette is ready!');
                $("output:first").val(s);
            })
        };

        function err() {
            dfd.fail(function (e) {
                msg('Oh no, omelette fail!');
                $("output:first").val(e);
            });
        };

        dfd.always(function () {
            $("output:last").val(dfd.state() + " at " + $.now())
        });

        function crackEggs(_resolveReject) {
            (_resolveReject === "reject" 
             ? dfd.reject(_resolveReject + " called at " + $.now()) 
             : dfd.resolve(_resolveReject + " called at " + $.now())
            );
            msg('Cracking eggs');
            return dfd.state();
        }

        function beatEggs() {
            msg('Beating eggs');
            return dfd.state();
        }

        function washTomatos() {
            msg('Washing tomatos');
            return dfd.state();
        }

        function chopTomatos() {
            msg('Chopping tomatos');
            return dfd.state();
        }

        function mixEggsAndTomatos() {
            msg('Mixing eggs and tomatos');
            return dfd.state();
        }

        function fryEggsAndTomatos() {
            msg('Frying eggs and tomatos');
            return dfd.state();
        }

        function msg(text) {
            $('#messages').append('<p>' + text + '</p>');
        }
    });
});

jsfiddle http://jsfiddle.net/guest271314/WWF68/

Другие вопросы по тегам