【问题标题】:How do we chain multiple promises that should happen one by one using jQuery?我们如何使用 jQuery 将多个应该发生的 Promise 链接起来?
【发布时间】:2017-05-13 18:59:09
【问题描述】:

以下是我们如何在 jQuery(1.8 及更高版本)中链接多个 Promise 的方式吗?

foo()
  .then(function() { return bar(); })
  .then(function() { return wah(); })   
  .then(function() { return lah(); })
  .then(function() { return haha(); });

所有foo()bar()wah()lah()haha() 都必须返回一个承诺。

我想一个注意点是我们必须使用then()而不是done(),因为如果我们使用done(),那么第二个动作到最后一个动作都将在动作1完成后开始,而不是一个接一个。


一个例子:https://jsfiddle.net/jq9d3tw1/

changeStyle($("#message1"), { fontSize: "3em" }, 3000)
  .then(function() { return changeStyle($("#message2"), { marginLeft: "100px" }, 2000) })
  .then(function() { return changeStyle($("#message3"), { opacity: 0 }, 1000) });

changeStyle() 创建一个 deferred,获取 Promise,执行一些操作并在完成时解析 Promise,然后返回该 Promise:

function changeStyle(element, style, duration) {

  var d = new $.Deferred(),
      p = d.promise();

  element.animate(style, duration, function() {
    d.resolve();
  });

  return p;
}

【问题讨论】:

  • 看看这篇文章,它很好地解释了链接多个承诺:medium.com/coding-design/…
  • where all foo(), bar(), wah(), lah(), haha() have to return a promise - 在您发布的代码 sn-p 中,只有 foo 必须返回一个承诺,其他 可以 但它不是 对于正确的 Promise/A+ 功能是必需的——当然,一些早期的 jQuery 实现的“promise”(或者更准确地说是 jQuery,Deferred 的)并不完全符合 Promise/A(更不用说 Promise/A+)了,所以,也许你是对的,那些函数必须返回一个 Promise
  • @JaromandaX 如果第二个和以后的返回一个承诺,如jsfiddle.net/jq9d3tw1/3 使用changeStyle2,那么动画2和3同时发生,不是一个一个
  • 你误会了。我只是更正了一个不正确的一般性陈述。
  • 所以你是说为了一个一个地做,倒数第二个函数不必返回一个承诺?你有这个工作的例子吗?因为jsfiddle.net/jq9d3tw1/3 没有

标签: jquery promise jquery-deferred deferred


【解决方案1】:

如果你返回 Promise,这段代码会更简单——你不需要在里面创建匿名函数

changeStyle($("#message1"), { fontSize: "3em" }, 3000)
  .then(changeStyle($("#message2"), { marginLeft: "100px" }, 2000))
  .then(changeStyle($("#message3"), { opacity: 0 }, 1000));

https://jsfiddle.net/vadimb/jq9d3tw1/1/

【讨论】:

  • 你确定...我看到所有动画同时发生,而不是一个接一个
  • no no no no - .then 的任何非函数参数都将被有效忽略 - 这不是链接任何东西
  • 但是会被评估,所以如果它是一个函数(函数调用)就可以采取行动
  • 确实,函数会被立即调用,所以上面的代码就像调用每个changeStyle一样,就像第一个没有.then( ... )
【解决方案2】:

对于这个特定的用例,jQuery 为您提供了使用queue 开箱即用的功能。默认情况下,fx 队列适用于动画,包括 fadeIn()slideUp() 等内置的。

在这种情况下,一旦当前元素的动画完成,done 函数就会触发对下一个元素的效果。

var $message1 = $('#message1');
var $message2 = $('#message2');
var $message3 = $('#message3');
$message1.queue(function() {
    $(this).animate(
      { fontSize: "3em" }, 
      {
        duration: 3000, 
        done : function() { $message2.dequeue(); }
      }
    );
});
$message2.queue(function() {
    $(this).animate(
      { marginLeft: "100px" },
      {
        duration: 2000, 
        done : function() { $message3.dequeue(); }
      }
    );
});
$message3.queue(function() {
    $(this).animate({ opacity: 0 }, 1000);
});
$message1.dequeue(); // initiate the first effect

查看我的JSFiddle 示例

【讨论】:

    【解决方案3】:

    您可以通过使用 .bind()then 回调和动画元素上的 .promise() 方法使代码更简洁:

    changeStyle($("#message1"), { fontSize: "3em" }, 3000)
      .then(changeStyle.bind($, $("#message2"), { marginLeft: "100px" }, 2000))
      .then(changeStyle.bind($, $("#message3"), { opacity: 0 }, 1000));
    
    function changeStyle(element, style, duration) {
      return element.animate(style, duration).promise();
    }
    body { font: 24px Arial, sans-serif; }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <div id="message1">hello</div>
    <div id="message2">hi</div>
    <div id="message3">ha</div>

    【讨论】:

    • 我宁愿绑定到null,但在没有必要的时候,而不是$
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-06-02
    • 1970-01-01
    • 2019-09-18
    • 1970-01-01
    • 2015-07-12
    • 2019-01-15
    • 1970-01-01
    相关资源
    最近更新 更多