【问题标题】:Deferred() only make 2 functions asynchronousDeferred() 仅使 2 个函数异步
【发布时间】:2017-03-16 00:52:08
【问题描述】:

小提琴:https://jsfiddle.net/x89ja8r8/

我一直在寻找一种快速链接函数异步的方法。 Stackoverflow 提供了很多“相同”的解决方案,但当我尝试时,总是有问题。

在下面的示例中,我有 3 个函数。我尝试使用 $.Deffer() 异步链接它们。

预期:div 将在 5500 毫秒内更改其尺寸,然后 div 将在 2000 毫秒内淡入 0.25 不透明度,然后 div innerHTML 将更改为 DONE!

结果:div 在 5500 毫秒内改变其 innerHTML(来自 fn3())同时 改变其尺寸(来自 fn1()),然后它在 2000 毫秒的持续时间内褪色到 0.25 的不透明度(来自 fn2())。

function fn1() {

  $("#result").animate({
    width: 800,
    height: 800
  }, 5500);

}

function fn2() {

  $("#result").animate({
    opacity: 0.25
  }, 2000);

}

function fn3() {

  $("#result").html("DONE!");

}

var dfr = $.Deferred();

dfr.done(fn1, fn2, fn3).resolve();

这里有什么问题?如果它根本不起作用,则 fn1() 和 fn2() 之间不应该存在异步。结果清楚地表明 fn2() 确实等待 fn1() 完成,但 fn3() 甚至没有等待就开始了。

【问题讨论】:

  • 按顺序运行的 2 个函数正在这样做,因为 .animate() 具有特殊行为,即在开始之前等待该元素上的所有其他动画完成。

标签: javascript jquery asynchronous promise jquery-deferred


【解决方案1】:

对于这个特定的用例,您可以使用简单的回调来代替$.Deferred

$("#result")
.animate({ width: 800, height: 800 }, 5500)
.animate({ opacity: 0.25 }, 2000, function () {
  $(this).text('Done!')
})
div {
  width: 100px;
  height: 100px;
  background-color: #ccc;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="result">Result</div>

【讨论】:

  • 嗨。谢谢您的建议。但是,我需要 Deferred() 因为我需要链接可能不是异步函数本身的函数()(纯 javascript)。如果你有 4 个函数,你会如何异步执行它们?
  • 嗨。我在这里尝试过jsfiddle.net/x89ja8r8/1,但没有达到预期的效果。
  • 嗨,环流。那个小提琴在 fn3() 上没有 2 秒的等待时间。目标是执行 fn1() 5.5 秒,然后执行 fn2() 2 秒,然后等待 2 秒执行 fn3(),然后 等待 2 秒执行 fn4()。跨度>
  • 这个想法是正确的,回旋。但是,fn4 不会等待 fn3 完成!两者同时触发,fn3和fn4之间没有等待。
  • 哦,我忘了把fn4的延迟改成4s。给你:jsfiddle.net/x89ja8r8/4
【解决方案2】:

我一直在寻找一种快速链接函数异步的方法。

done method 没有链接任何东西。它安装处理程序以运行,如果您传递多个参数,它将同时调用这些函数。永远不要使用done

您正在寻找的是then method 的promise,它返回一个新的promise,它将用回调的结果来解决(当它返回另一个promise 时等待)。实际上你根本不需要延迟!

function fn1() {
  return $("#result").animate({
    width: 800,
    height: 800
  }, 5500).promise();
}
function fn2() {
  return $("#result").animate({
    opacity: 0.25
  }, 2000).promise();
}
function fn3() {
  $("#result").html("DONE!");
}

fn1().then(fn2).then(fn2);

【讨论】:

    【解决方案3】:

    dfr.done(fn1, fn2, fn3) 将同时执行所有函数,而不是按顺序执行。由于 $.animate() 是一个异步操作,根据 jQuery 的文档,它可以接受一个回调,一旦动画完成就会被调用,或者你可以让它返回一个承诺。然后,您将不得不使用 $.Deferred.then() 链接承诺,如下所示:

    $(document).ready(function() {
      function fn1() {
        return $("#result").animate({
          width: 800,
          height: 800
        }, 5500).promise();
      }
    
      function fn2() {
        return $("#result").animate({
          opacity: 0.25
        }, 2000).promise();
      }
    
      function fn3() {
        return $("#result").html("DONE!").delay(2000).promise();
      }
    
      function fn4() {
        var fn4Dfr = $.Deferred();
        setTimeout(function() {
          $("#result").html("Okay!");
          fn4Dfr.resolve();
        }, 2000);
        return fn4Dfr;
      }
    
      var dfr = $.Deferred();
      dfr.then(fn1).then(fn2).then(fn3).then(fn4);
      dfr.resolve();
    });

    fn3 使用延迟,其行为类似于 setTimeout,而 fn4 使用 setTimeout,因此我们创建了一个可以根据需要解决的承诺(并立即返回该承诺)。

    【讨论】:

    • 你好,鲍。谢谢您的答复。现在我知道 $.animate() 本身是异步的,如果我有另一个不是异步函数的 fn4() 会发生什么?那我该如何链接它们,因为我在这里尝试过jsfiddle.net/x89ja8r8,但它没有按预期工作。
    • 我包含了一个使用 $.delay() 的示例,它在 fn3 中有一个承诺。对于 fn4,如果您决定执行没有承诺的事情,那么您可以创建一个并在完成后解决。 jsfiddle.net/52fvv0xw
    • 那么,给定一个纯 javascript 函数 fn(){ /*code goes here */ },有没有办法让这个函数成为 jQuery 的承诺?
    • 我刚刚更新了我的答案jsfiddle.net/52fvv0xw 以fn4为例。
    • 完美,宝。您能否更新该小提琴作为您的答案。这正是我想要的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多