【问题标题】:Chaining jQuery promises in parallel using simple alternative to $.when.apply使用 $.when.apply 的简单替代方法并行链接 jQuery Promise
【发布时间】:2015-05-10 01:44:04
【问题描述】:

当顺序使用 jQuery Promise 时,可以重复使用 then 链接它们:

例如

promise = promise.then(someoperation());

这也适用于循环(非常方便)。

我有类似的场景,我需要知道多个并行操作何时完成,但不经历为调用而创建一组承诺的编码开销(例如增加的复杂性) $.when.apply

在查看了我的选项后,我想出了这个模式作为替代方案:

promise = $.when(promise, anotherpromise);

为了测试它,我想出了这个测试:

var p = $.Deferred().resolve().promise();

[1,2,3,4,5,6,7,8,9,10].forEach(function(i){
     p = $.when(p, delay(i,i * 500));
});

p.then(function(){
   log("All done");
});

JSFiddle: http://jsfiddle.net/TrueBlueAussie/0rh8Lhv4/1/

这似乎工作得很好,所以我开始将它应用到 StackOverflow 上的其他示例。

我尝试使用此模式的下一个方法是修复 Pass in an array of Deferreds to $.when() 中的示例:

我的代码:

$("a").click(function () {
    var promise = GetSomeDeferredStuff();
    promise.then(function () {
        $("div").append("<p>All done!</p>");
    });
});

JSFiddle: http://jsfiddle.net/TrueBlueAussie/ts1dqwe3/1/

问。由于某种原因,这个永远不会触发最终事件。谁能发现问题?

更新

根据@Karl-André Gagnon 的评论,最初的promise 似乎可以未定义并且仍然有效。简单得多:

例如

var p;
[1,2,3,4,5,6,7,8,9,10].forEach(function(i){
     p = $.when(p, delay(i,i * 500));
});
p.then(function(){
   log("All done");
});

【问题讨论】:

  • 你说创建一个承诺数组将是开销。你认为多次调用$.when 的开销是多少?!
  • 另外,你最外层的promise最终解决的结果完全被搞砸了。
  • @Bergi:我的意思是编码开销。不是内存开销。开销是一系列承诺而不是承诺数组。关于你的第二条评论,你能用技术措辞澄清一下吗? “完全被搞砸了”并没有真正为我做这件事:)
  • 我认为通过使用map 而不是forEach 类型的循环可以减轻(甚至逆转)“编码开销”。在我的第二条评论中,我的意思是说 p 最终解决的值(应该是一个结果数组,并且是一个合理的解决方案)是完全无法使用的,它是某种嵌套元组(甚至不是一个缺点列表)

标签: javascript jquery promise jquery-deferred


【解决方案1】:

好的,事实证明这种模式确实可以正常工作,但是您需要确保链接到的初始 promise 已经解决:

function GetSomeDeferredStuff() {
    var promise = $.Deferred().resolve().promise();

JSFiddle: http://jsfiddle.ne/TrueBlueAussie/ts1dqwe3/2/

总而言之,这种模式确实创建一个仅供$.when.apply使用的数组的简单替代方案。

另外,正如@Karl-André Gagnon 所指出的,如果您从一个未定义的值开始,它会做同样的事情。更好:)

function GetSomeDeferredStuff() {
    var promise;

JSFiddle: http://jsfiddle.net/TrueBlueAussie/ts1dqwe3/4/

【讨论】:

  • 为什么要先声明一个空的延迟对象?将undefined 传递给when 只需忽略它:jsfiddle.net/ts1dqwe3/3。我错过了什么吗?
  • @Karl-André Gagnon:错过了那个小技巧(更新)。这使得整个解决方案现在非常整洁。比数组上的 $.when.apply 简单得多。谢谢。 :)
  • 需要考虑的是创建的 Promise 的数量。使用$.when.apply($, array)N + 1 个承诺。使用循环 $.when(promise, ...): 2N 承诺。另外,consider the usefulness of the final result.
  • @Roamer-1888:是的,它可能是 2N,但在许多情况下(ajax 限制等),开销是合理的。作为返回值,值得进一步研究以测试该技术的局限性。与$.when.apply 一起使用的数组的结果通常也不会使用/不可用(例如,如果没有对arguments 的通用处理,则不会)。这只是要知道操作何时完成。我将继续调查这种方法的利弊并更新我的发现。
  • @Roamer-1888:您可能也希望批评这个答案,因为它被认为是“优雅的”,并且是解决这个问题的鸽子对:stackoverflow.com/questions/30096628/…
【解决方案2】:

更新

我有类似的情况,我需要知道何时多个并行 操作已完成,但没有经历创建的开销 一组仅用于调用的承诺

loop 未使用;只有$.when();与通过 $.map() 实现时使用的模式相同。此外,将“随机”delay 添加到 jsfiddle ajax request ;在$.when() 的所有并行函数调用完成、next 已调用、queueName 队列为空之前,不应调用 promise.then()

function GetSomeDeferredStuff(elem, name, cycles) {
    var el = (elem || {}),
        queueName = (name || "q"),
        len = (cycles || 5),
        request = function () {
            return $.ajax({
                type: "POST",
                url: '/echo/html/',
                data: {
                    html: "<p>Task #" + $.now() + " complete.",
                    delay: Math.random() * 5
                },
                success: function (data) {
                    $("div").append(data);
                }
            })
        }
    return $(el).queue(queueName, function (next) {
        return $.when(request()
                      , request()
                      , request()
                      , request()
                      , request())
                      .then(next)
    }).dequeue(queueName).promise(queueName);
}

$(function () {
    $("a").click(function () {
        var promise = GetSomeDeferredStuff();
        promise.then(function () {
            $("div").append("<p>All done!</p>");
        });
    });
});

jsfiddle http://jsfiddle.net/ts1dqwe3/10/


当顺序使用 jQuery Promise 时,可以将它们链接起来 然后反复使用 ... 这也适用于循环(非常方便)。

尝试使用.queue() .promise(queueName)

function GetSomeDeferredStuff(elem, name, cycles) {
    // if no `elem`:`this` object passed , utilize empty object `{}`
    var el = (elem || {})
          // if no `name` passsed, utilize `String` `"q"`
        , queueName = (name || "q")
          // if no `cycles` how many functions passed to `.queue(queueName)`,
          // pass `5` functions to `.queue(queueName)`
        , len = (cycles || 5);
    return $(el).queue(queueName
    , $.map(Array(len), function (_, index) {
        return function (next) {
            return $.ajax({
                type: "POST",
                url: '/echo/html/',
                data: {
                    html: "<p>Task #" + (1 + index) + " complete.",
                    delay: (index + 1) / 2
                },
                success: function (data) {
                    return $("div").append(data);
                }
            // call "next" function in `queue`
            }).then(next)
        }
       // `.dequeue(queueName)` , return `queueName` jQuery promise object,
       // when all functions in `queue(queueName)` called ; 
       // `.queue(queueName)` empty
    })).dequeue(queueName).promise(queueName);
}

$(function () {
    $("a").click(function () {
        var promise = GetSomeDeferredStuff();
        promise.then(function () {
            // `this`:`elem` , or `{}`
            $("div").append("<p>All done!</p>");
        });
    });
});

jsfiddle http://jsfiddle.net/ts1dqwe3/6/

【讨论】:

  • 很好,虽然比其他替代方案可读性差一些,但这个问题是关于承诺的并行处理。
猜你喜欢
  • 1970-01-01
  • 2014-02-26
  • 2011-04-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多