如何按顺序执行javascript?

how to execute javascript deferred sequentially?

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

知道如何用 Jquery deferred 修补它。

编辑:

在我理解 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。然而,我没有看到任何结构可以帮助我轻松实现我想要的。

编辑 2:

我发现了以下库,如果您不介意启动许多并行任务,它非常有用。事实上它可以 return 在第一个成功的时候。它是对 When 的修改。尽管我认为不必全部调用它们会很好

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

编辑 3:

我更想寻找一个完全没有错误的库,可以像 https://codereview.stackexchange.com/questions/38420/sequential-function-call-in-javascript or Conditionals on a chained deferred in jquery

EDIT4: Update based on the response by @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。

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

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

(其中 step1()step2()step3() return 延迟对象)

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

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

When-JS 恰到好处。这就是我要找的

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

通俗地说,objective 可以概括如下:

"At each turn of a loop, if neither a broader-concept NOR a narrower-concept is discovered (asynchronously), then continue to test, otherwise break out of the loop".

在同步代码中这是微不足道的,但在异步世界中有一些障碍需要跳过。特别是,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())修改为 return 一个将是 resolved/rejected 的承诺,而不是将用布尔值 [=41] 解析的承诺=](还有其他小改动):

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() 链。
  • 使用自定义方法 $.when_none() 实现所需的 NOR 逻辑以控制承诺链。
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 逻辑,但我现在想不出来。