Верижно обещание при използване на $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/


person twip    schedule 08.03.2016    source източник


Отговори (3)


Не извиквайте функциите вътре в методите .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 незабавно в масива.

ДЕМО на JSFiddle

person georgeawg    schedule 08.03.2016
comment
Това също е доста интересно решение. - person Satej S; 08.03.2016
comment
Много ясно казано. Каква разлика могат да направят тези двойки в скоби. - person twip; 08.03.2016
comment
Това ми помогна изключително много - person Fergus; 26.08.2017
comment
Какво ще кажете за функции с множество аргументи? - person firstpostcommenter; 22.01.2021
comment
ясно. Но трябва да извикам функция function1 и след това да извикам друга функция function2, след като function1 бъде разрешен, защото имам нужда от резултата от function1. Но function2 също има някои други допълнителни аргументи, които са налични в .js файла.... Вероятно трябва също да изпратя тези стойности на функция1 и да накарам функция1 да върне резултат, който също има тези променливи, които след това могат да бъдат използвани във функция2? - person firstpostcommenter; 23.01.2021
comment
@firstpostcommenter Моля, задайте това като нов въпрос. Разделът за коментари трябва да се използва само за изясняване на съществуващия отговор. Тук дългите дискусии не са подходящи. Също така погледнете реда за изпълнение на AngularJS с $q — Chaining Promises - person georgeawg; 23.01.2021

Заповядай. Това, което направих, е по същество да добавя функция success в частта then на кода.

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

Ето работещото демо.

Можете също да добавите error function като този

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

Докато търсех този отговор, попаднах и на тази много полезна връзка

person Satej S    schedule 08.03.2016
comment
Това е отлично напомняне за основната структура на API; Благодаря ти. - person twip; 08.03.2016

Както други споменаха - вашият по-голям проблем е, че вие ​​.then(promise), а не .then(function).

Обещанията представляват стойност + време. Това е резултат от вече започнала операция. Обещанието е стойност - then чака функции. Не можете да "пускате обещание след друго обещание" - тъй като обещанието означава, че операцията вече е започнала.

Когато then(x) за нещо различно от функция, то се игнорира. Това е неудачен избор в спецификацията на обещанията, но трябва да живеем с него.

Тъй като вашите обаждания са синхронни, не трябва да използвате обещания за него. Ако вашият код прави нещо синхронно, можете да последователно извършвате действия с ;, а не с then:

pushA();
pushB(); 

Ако това е обаждане, което връща обещания, то просто става:

pushA().then(pushB);

Няма смисъл да се извиква $q.when, което преобразува необещания в обещания.

Бих го написал като:

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

Няма смисъл да се преобразува първото синхронно действие във функция за връщане на обещание или да се включват обещания навсякъде освен времето за изчакване. Ако имате нужда pushA да се случи след самите 5000ms, вероятно ще напиша:

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

Тъй като мисля, че е по-четлив и отново не включваме pushA и pushB с обещания директно.

person Benjamin Gruenbaum    schedule 08.03.2016
comment
Благодаря ви за отговора. Понякога е много трудно да се улови добре намерението, докато сте едновременно кратки и ясни за SO публикации. Това, което се опитвах да уловя, е сценарий, при който възнамеряваме A да бъде решен преди B, а A е обещанието, което трябва да носи забавянето. Значение: Бих искал pushA да завърши работата си, включително забавянето, и тогава и само тогава да изпълни pushB. Ето една актуализирана цигулка, внедрена с вашите данни, която ми помогна да стигна до това, което търсех: jsfiddle.net/ nam3cbaw/1 - person twip; 08.03.2016