【问题标题】:Preventing a function from running if a parallel function has already failed (using jQuery $.when())如果并行函数已经失败,则阻止函数运行(使用 jQuery $.when())
【发布时间】:2014-09-09 18:08:16
【问题描述】:

我在 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 函数的运行。

你可以看到an example here

我对此的担忧是,在我的实际代码中,我不希望浏览器对服务器进行 AJAX 调用,这可能会改变状态,如果没有意义,因为整个过程已经失败.

有没有办法做我想做的事?我想我可以将失败处理程序单独附加到每个并行任务,但我想知道是否有一种不那么冗长/重复的方式。

谢谢!

【问题讨论】:

  • “大多数情况下,这是可行的——除了一种情况。如果打鸡蛋时失败,那么番茄仍然会被清洗和切碎”。是否要求如果crackEggs()washTomatos() 的错误不会继续?谢谢
  • 如果在 crackEggs() 期间到 washTomatos() 应启动时已经发生错误,则不应执行 washTomatos()。任何并行任务也是如此 - 如果在任务开始之前发生故障,则不应执行该任务。所以这更像是一个普遍的要求。

标签: javascript jquery jquery-deferred


【解决方案1】:

试试(这个模式)

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 https://jsfiddle.net/guest271314/WWF68/

【讨论】:

    【解决方案2】:

    为状态添加一个变量。例如在done( var status = 1 )fail( var status = 2 的内部,然后在并行函数运行之前放置一个简单的语句,这样如果status = 2 就不会运行。

    【讨论】:

    • 我倾向于认为这就是答案,即没有带有承诺/延迟的内置机制可以处理这个问题,因此开发人员必须自己处理。
    猜你喜欢
    • 2022-12-16
    • 2017-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-27
    • 1970-01-01
    相关资源
    最近更新 更多