Цепочная цепочка при использовании $timeout

Я пытаюсь понять API обещаний и цепочку, особенно время, когда $timeout используется с .then(). То, что я ожидал от следующего, состоит в том, что, поскольку $timeout возвращает обещание, .then() не будет вызываться до тех пор, пока он не будет разрешен.

Но вместо ABAB это ABBA все время.

Как я могу использовать 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/

Ответ 1

Не вызывайте функции внутри методов .then.

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

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

Вместо этого передайте функции как аргументы методу .then. Служба $q будет содержать эти функции, которые будут вызываться позже.

Как работает служба $q, он сохраняет аргумент метода .then как функцию, которая будет вызвана позже. В этом случае служба $q сохраняла значение, возвращаемое pushB(), с побочным эффектом нажатия B сразу на массив.

DEMO на JSFiddle

Ответ 2

Здесь вы идете. То, что я сделал, по существу добавило функцию success в части then кода.

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

Вот рабочая демонстрация .

Вы также можете добавить error function, как этот

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

При поиске этого ответа я также столкнулся с этой полезной ссылкой

Ответ 3

Как уже упоминалось, ваша большая проблема заключается в том, что вы .then(promise), а не .then(function).

Promises представляют значение + время. Это результат уже запущенной операции. Обещание - значение - then ждет функций. Вы не можете "выполнить обещание после другого обещания" - поскольку обещание означает, что операция уже началась.

Когда вы then(x) для чего-либо, кроме функции, игнорируются. Это неудачный выбор в спецификации promises, но мы должны жить с ним.

Поскольку ваши вызовы синхронны, вы не должны использовать для этого promises. Если ваш код делает что-то синхронное, вы можете выполнять действия с помощью ;, а не then:

pushA();
pushB(); 

Если это вызов, который возвращает promises, тогда он просто становится:

pushA().then(pushB);

Нет смысла вызывать $q.when, который преобразует не promises в promises.

Я бы написал его как:

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

Нет смысла преобразовывать первое синхронное действие в функцию возврата обещания или включать promises в любом месте, кроме таймаута. Если вам понадобится pushA, чтобы произойти после 5000 мс, я бы, вероятно, написал:

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

Так как я думаю, что это более читаемо, и мы снова не связаны с pushA и pushB с promises.