【问题标题】:how to execute javascript deferred sequentially?如何按顺序执行延迟的javascript?
【发布时间】:2015-07-24 03:32:40
【问题描述】:

我想知道是否有办法按顺序和有条件地执行延迟任务。也就是说,我想按顺序执行一些异步任务,我只会根据前一个的结果执行下一个。 Promise 链的结果应该是最后执行的。

知道如何使用延迟的 Jquery 来修补它。

编辑:

在我正确理解 ajax 调用之前,我为一个函数启动了以下代码,该函数验证一个值不在另一个值的相关值中。

function findBroaderOrNarrowerConceptInFieldSelectedList(field, value) {

    var intputfields = $("#instance_" + field + "_wrapper" + " .ds-authority-value")

    if (intputfields.length == 0)
        return undefined;

    //go over each input field and retreive the value

    for (var i = 0; i < intputfields.length; i++) {
        //check if our value is in the broader concepts of the input field concept
        //if true return the wrapper element, if false next steps
        if (is_broader_concept(value.id, $(intputfields[i]).attr('value'))) {

            var WrapperdivId = "#" + $(intputfields[i]).attr('name').replace("_authority", "") + "_wrapper";

            return $($(WrapperdivId)[0]);
        }
        //check if our value is in the narrower concepts of the input field concept
        //if true return the wrapper element
        if (is_narrower_concept(value.id, $(intputfields[i]).attr('value'))) {

            var WrapperdivId = "#" + $(intputfields[i]).attr('name').replace("_authority", "") + "_wrapper";

            return $($(WrapperdivId)[0]);
        }
    }

    return undefined
}

问题是我的 is_broader_concept 看起来像这样:

function is_broader_concept(broaderuri, concepturi) {

    return getBroaderConcepts(concepturi).then(function(data, textStatus, jqXHR ) {

        var broaders = data

        if (broaders.length == 0)
            return false;

        for (var i = 0; i < broaders.length; i++) {

            if (broaders[i].uri == broaderuri)
                 return true;
        }
    });
}

现在我已经了解了 deferred 和 promise(不是很新,因为我在 scala 中做过(promise 和 future)),我想调整我的第一个方法来使用 deferred。但是我没有看到任何可以帮助我轻松实现我想要的结构。

EDIT2:

我发现以下库非常好,以防您启动许多并行任务。事实上,它可以在第一个成功的情况下返回。这是对When的修改。虽然我认为不必打电话给所有这些人会很好

https://github.com/terrycojones/jquery-when2

EDIT3:

我更多的是寻找一个完全没有错误的库,可以在 https://codereview.stackexchange.com/questions/38420/sequential-function-call-in-javascriptConditionals on a chained deferred in jquery 中执行类似操作

EDIT4:根据@Roamer-1888 的响应进行更新

正确的 is_broader 和较窄的适用于他的解决方案

function is_broader_concept_Promise(broaderuri, field) {

    var uri = field.value.substr(field.value.indexOf("http://"));

    return getBroaderConcepts(uri).then(function(data, textStatus, jqXHR ) {

        var broaders = data;

        if (broaders.length == 0)
            return $.Deferred( function( d){ d.reject(); }).promise();

        for (var i = 0; i < broaders.length; i++) {

            if (broaders[i].uri == broaderuri)
                return field;
        }
        return $.Deferred( function( d){ d.reject(); }).promise();
    });
}

function is_narrower_concept_Promise(narroweruri, field) {

    var uri = field.value.substr(field.value.indexOf("http://"));

    return getNarrowerConcepts(uri).then(function(data, textStatus, jqXHR ) {

        var narrowers = data;

        if (narrowers.length == 0)
            return $.Deferred( function( d){ d.reject(); }).promise();

        for (var i = 0; i < narrowers.length; i++) {

            if (narrowers[i].uri == narroweruri)
                return field;
        }
        return $.Deferred( function( d){ d.reject(); }).promise();
    });
}

非常感谢,

中号

PS:我大约一个月前开始使用 jQuery。

【问题讨论】:

  • 把你的例子(或任务)带到桌面
  • 顺序任务从何而来?您如何/在哪里打电话给is_broader_concept()
  • 在“findBroaderOrNarrowerConceptInFieldSelectedList”的“for”里面
  • "getBroaderConcepts(concepturi)" 是异步 ajax 调用完成的地方。

标签: jquery jquery-deferred


【解决方案1】:

.done() 处理程序只有在任务成功时才会触发,因此您可以像这样使用嵌套的done() 处理程序:

step1().done(function() {
    step2().done(function() {
        step3().done(function() {
            // etc.
        });
    });
});

(其中step1()step2()step3() 返回延迟对象)

如果您正在制作自己的延迟对象,您可以调用deferred.resolve() 表示任务成功,或调用deferred.reject() 表示任务失败。

有关详细信息,请参阅jQuery.Deferred() 文档。

【讨论】:

  • 根据我在文档中的红色,完成,安装多个将立即执行的回调,因为完成,返回原始对象。到目前为止,该方法似乎正在使用“then”
  • 只有在你将它们串联起来的情况下,它们才会同时执行,即.done().done()。如果您使用嵌套的done 调用,它们应该按顺序执行。
  • 但是,是的,您也可以像我使用 done() 的方式一样使用 then()
  • 我建议使用.then(),因为它是使用承诺的标准实现方式。 .done() 是一个非标准的 jQuery 实现。
【解决方案2】:

用简单的语言可以将目标总结如下:

“在循环的每一轮,如果(异步)没有发现更广泛的概念或更窄的概念,则继续测试,否则退出循环”。

在同步代码中这将是微不足道的,但在异步世界中需要跳过一些障碍。特别是,jQuery 不为异步NOR 提供语法糖。但是,我们可以以自定义jQuery.when_none() 方法的形式编写一个:

jQuery.when_none = function() {
    //if all input-promises reject, then fulfil.
    //if any input-promise fulfills, then reject.
    var promises = $.map(arguments, function(p) {
        return $.Deferred(function(dfrd) {
            p.then(dfrd.reject, dfrd.resolve);//resolve/reject inversion
        }).promise();
    });
    return $.when.apply(null, promises);
};

接下来,修改is_broader_concept()(和is_narrower_concept())以返回一个将被解析/拒绝的promise,而不是一个将通过布尔真/假解析的promise(还有其他小的更改):

function is_broader_concept(uri, fld) {
    return getBroaderConcepts(fld.value).then(function(data) {
        if(data.indexOf(uri) > -1) {
            return fld; // The success state will be inverted by $.when_none(), and the rest of the .then() chain will be bypassed
        } else {
            return $.Deferred().reject().promise(); // The fail state will be inverted by $.when_none(), permitting the next step of the .then() chain.
        }
    });
}

最后,findBroaderOrNarrowerConceptInFieldSelectedList()

  • 通过利用.reduce() 循环访问“.ds-authority-value”字段来构建.then() 链。
  • 使用cutom方法$.when_none()实现所需的NOR逻辑来控制promise链。
function findBroaderOrNarrowerConceptInFieldSelectedList(field, value) {
    return $("#instance_" + field + "_wrapper").find(".ds-authority-value").get().reduce(function(promise, fld) {
        return promise.then(function() {
            return $.when_none(
                is_broader_concept(value.id, fld),
                is_narrower_concept(value.id, fld)
            );
        });
    }, $.when()).then(function() {
        /* success: ie "not found", so reinvert the logic to force down the fail path */
        return $.Deferred().reject(value.id + ' is neither broader-concept nor narrower-concept.');
    }, function(fld) {
        /* fail: ie "found", so reinvert the logic to force down the success path */
        return $.when($('#' + fld.name.replace('_authority', '') + '_wrapper')); // $(fld) ???
    });
}

可能有更简单的方法来实现 NOR 逻辑,但我现在想不出。

【讨论】:

  • 其实函数is_broader_concept(is_narrower_concept)是不对的。逻辑是我有 A 和 B,想知道 A 是否比 B 更宽/更窄。我得到了 B 的 Narrower/Broader 概念,并检查 A 是否是它的一部分。
  • 在 findBroaderOrNarrowerConceptInFieldSelectedList 中,我不了解您对 reduce 的操作。你能用简单的英语解释更多的逻辑吗?也许那时我可以理解代码。我需要了解传递给函数的参数(承诺,字段)。如果我现在可以猜出对您来说意味着什么,我不明白什么是承诺。我认为通常我不理解传递给 reduce 的函数,以及 reduce 传递给该函数的参数。也许那时我会更好地理解。请,如果你能澄清这会有所帮助
  • Maat,是的,.reduce() 是这个答案的核心。 “The Collection Kerfuffle”一节中的最后一个示例here 解释了它。
  • 我已经编辑了代码以避免重复使用field,这很令人困惑。现在,fld 等价于您原来的intputfields[i]fld.value 等价于$(intputfields[i]).attr('value')
  • 我试图在问题中实现更广泛/更窄逻辑的更正版本,但可能弄错了。这肯定与您上面的 A/B 描述不同,我不确定如何更正。
【解决方案3】:

When-JS 会做得恰到好处。这就是我一直在寻找的

https://github.com/cujojs/when/blob/master/docs/api.md#api

【讨论】:

  • Maat,请您多说一些。 when.js 有什么帮助?我们可以看看你的最终代码吗?
  • 到目前为止,我只看到如何将其作为比赛形式进行。当一个结果为真时,返回真。否则,迭代似乎很难使用。我正在努力。
  • 是的,即使使用 when.js 也不是很简单。我将发布一个 jQuery 解决方案,这可能会有所帮助。
猜你喜欢
  • 2013-11-19
  • 2013-04-29
  • 2014-09-15
  • 2016-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-25
  • 1970-01-01
相关资源
最近更新 更多