【问题标题】:Promise chaining when using $timeout使用 $timeout 时的承诺链
【发布时间】:2020-02-14 23:15:04
【问题描述】:

我正在尝试了解 Promise API 和链接,尤其是 $timeout.then() 一起使用的时机。我对以下内容的期望是,由于$timeout 返回一个承诺,.then() 在解决之前不会被调用。

但不是 ABAB,而是 ABBA。

如何使用 Promise API 确保长时间运行的调用(或使用 $timeout 的延迟调用)在 .then() 执行之前实际上完成?

代码

angular
  .module('app', [])
  .controller('ThenCtrl', ThenCtrl);

function ThenCtrl($timeout, $q) {
  var vm = this;

  vm.items = [];

  $q.when(pushA()).then(pushB());

  $timeout(pushA, 5000).then(pushB());

  function pushA() {
    vm.items.push('A');
  }

  function pushB() {
    vm.items.push('B');
  }
}

标记

<div ng-app="app">
  <div ng-controller="ThenCtrl as vm">
    {{vm.items}}
  </div>
</div>

我已经设置了一个小提琴:https://jsfiddle.net/kan3c61t/

【问题讨论】:

    标签: angularjs angular-promise


    【解决方案1】:

    不要调用 .then 方法中的函数。

      ̶$̶q̶.̶w̶h̶e̶n̶(̶p̶u̶s̶h̶A̶(̶)̶)̶.̶t̶h̶e̶n̶(̶p̶u̶s̶h̶B̶(̶)̶)̶;̶
      $q.when(pushA()).then(pushB);
    
      ̶$̶t̶i̶m̶e̶o̶u̶t̶(̶p̶u̶s̶h̶A̶,̶ ̶5̶0̶0̶0̶)̶.̶t̶h̶e̶n̶(̶p̶u̶s̶h̶B̶(̶)̶)̶;̶    
      $timeout(pushA, 5000).then(pushB);
    

    而是将函数作为参数传递给.then 方法。 $q 服务将保存这些函数以供以后调用。

    $q 服务的工作方式是将.then 方法的参数存储为稍后调用的函数。在这种情况下,$q 服务正在存储pushB() 返回的值,其副作用是将B 立即推送到数组中。

    DEMO on JSFiddle

    【讨论】:

    • 这也是一个非常有趣的解决方案。
    • 说得很清楚。这些括号对可以产生多大的影响。
    • 这对我帮助很大
    • 具有多个参数的函数呢?
    • @firstpostcommenter 请将此作为一个新问题提出。评论部分应该只用于澄清现有的anwser。在这里不宜进行冗长的讨论。另请看AngularJS execution order with $q — Chaining Promises
    【解决方案2】:

    给你。 我所做的实际上是在代码的then 部分添加了success 函数。

    $timeout(pushA, 5000).then(function(success) {
        pushB()
      });
    

    这是工作的demo

    你也可以像这样添加error function

     $timeout(pushA, 5000).then(function(success) {
        pushB()
      },function(error){console.log("Error");});
    

    在寻找这个答案时,我也遇到了这个helpful link

    【讨论】:

    • 这是对底层 API 结构的一个很好的提醒;谢谢。
    【解决方案3】:

    正如其他人所提到的 - 你更大的问题是你 .then(promise) 而不是 .then(function)

    Promise 代表一个值 + 时间。这是已经开始操作的结果。承诺是一个值 - then 等待 函数。你不能“一个接一个地运行一个promise”——因为一个promise意味着操作已经开始。

    当您 then(x) 用于 函数 以外的任何内容时,它会被忽略。这是 Promise 规范中的一个不幸的选择,但我们必须忍受它。

    由于您的调用是同步的,因此您不应为此使用 Promise。如果您的代码执行同步操作,您可以使用; 而不是then 对操作进行排序:

    pushA();
    pushB(); 
    

    如果它是一个返回承诺的调用,那么它就变成了:

    pushA().then(pushB);
    

    调用 $q.when 将非承诺转换为承诺是没有意义的。

    我会这样写:

    pushA();
    $timeout(5000).then(pushB); 
    

    没有必要将第一个同步操作转换为一个 Promise 返回函数,或者在除了超时之外的任何地方都包含 Promise。如果您需要 pushA 在 5000 毫秒之后发生,我仍然可能会写:

    $timeout(5000).then(pushA).then(pushB)
    

    因为我认为它更具可读性,而且我们不直接将 pushApushB 与 Promise 相关联。

    【讨论】:

    • 感谢您的回复。有时很难很好地捕捉意图,同时对 SO 帖子既简短又清晰。我试图捕捉的是我们打算在 B 之前解决 A 的场景,而 A 是必须进行延迟的承诺。含义:我希望pushA 完成它的工作,包括延迟,然后仅执行pushB。这是一个更新的小提琴,使用您的输入实现,它帮助我找到了我正在寻找的东西:jsfiddle.net/nam3cbaw/1
    猜你喜欢
    • 2017-08-14
    • 1970-01-01
    • 1970-01-01
    • 2016-08-11
    • 1970-01-01
    • 1970-01-01
    • 2018-09-04
    • 2015-07-08
    • 2013-12-03
    相关资源
    最近更新 更多