【问题标题】:Generate from array sequential executions with deferreds (jquery)从具有延迟的数组顺序执行生成(jquery)
【发布时间】:2017-02-07 17:26:03
【问题描述】:

有没有办法使用其他解决方案使这个更优雅(jquery 很好)?

在我的情况下重要的是,只有在先前的执行被终止时才会触发相应的执行。

seqExe(["item one", "item two", "item three", "item four", "item five"])

function seqExe(corpus) {
    var i = -1,
        len = corpus.length,
        defer = jQuery.Deferred(),
        promise = defer.promise();

    while(++i < len) {
        promise = promise.then((function(item) {
            return function() {
                console.log(item);
                return foo(item);
            }
        }).call(this, corpus[i]));
    }

    promise.then(function() {
        console.log("Done");
    }, function() {
        console.error("Failed");
    });

    return defer.resolve();
}

function foo(item) {
    var defer = jQuery.Deferred();
    window.setTimeout(
        function() {
            defer.resolve()
            console.log(item);
        }, Math.random() * 2000 + 1000);

    return defer.promise();
}
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"&gt;&lt;/script&gt;

假设的输出应该是:

item one
item one
item two
item two
item three
item three
item four
item four
item five
item five
Done

【问题讨论】:

    标签: javascript jquery promise deferred


    【解决方案1】:

    这是使用reduce 的理想选择。此外,您的初始承诺(您想立即解决)可以只是 $.when(),并将成为 reduce 调用的起始值:

    seqExe(["item one", "item two", "item three", "item four", "item five"])
    
    function seqExe(corpus) {
        return corpus.reduce(function (p, item) {
            return p.then(function () {
                console.log(item + ' pending');
                return foo(item);
            });
        }, $.when())
        .then(function(){
            console.log("Done");
        }, function(){
            console.log("Failed");
        });
    }
    
    function foo(item) {
        var defer = new $.Deferred();
        window.setTimeout(
            function() {
                defer.resolve()
                console.log(item + ' resolved');
            }, Math.random() * 2000 + 1000);
        return defer.promise();
    }
    &lt;script src="https://code.jquery.com/jquery-3.1.1.min.js"&gt;&lt;/script&gt;

    请注意,在某些 jQuery 版本中(我在 2.1.1 中看到了这一点)then 回调是同步执行的,这会给出错误的输出顺序。这是在 jQuery 3 中修复的(我尝试了 3.1.1,我也在上面的 sn-p 中链接到)。

    以下是使用原生 ES6 承诺的方法:

    seqExe(["item one", "item two", "item three", "item four", "item five"])
    
    function seqExe(corpus) {
        return corpus.reduce(function (p, item) {
            return p.then(function () {
                console.log(item + ' pending');
                return foo(item);
            });
        }, Promise.resolve())
        .then(function(){
            console.log("Done");
        }, function(){
            console.log("Failed");
        });
    }
    
    function foo(item) {
        return new Promise(function (resolve) {
            window.setTimeout(function() {
                resolve();
                console.debug(item + ' resolved');
            }, Math.random() * 2000 + 1000);
        });
    }

    【讨论】:

    • 然后同步执行回调,这会给出错误的输出顺序。”是什么意思?这只可能发生在已经实现的承诺上,即$.when(),但第一个foo()调用之后的所有内容都是链式的。
    • @Bergi,我的意思是,如果在我发布的 sn-p 中,我链接到 jQuery 版本 2.1.1 而不是 3.1.1,输出的顺序就会改变。注意:我现在进行了更正,因为我首先移动了第二个 console.log,但忘记将其放回原处(解决后)。
    • 啊,那个。是的,您必须将 console.debug 放在 deferred.resolve() 调用之前。
    • 确实,这是我在意识到这是 jQuery 2 的一种特殊行为之前尝试过的。
    猜你喜欢
    • 2014-09-15
    • 2016-12-01
    • 2013-04-29
    • 2013-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-29
    • 1970-01-01
    相关资源
    最近更新 更多