【问题标题】:How to wait for few HTTP promises to complete and show a modal only if all the promises fail如何等待几个 HTTP 承诺完成并仅在所有承诺都失败时才显示模式
【发布时间】:2018-01-18 21:19:18
【问题描述】:

我在一个页面上有两个 HTTP 调用,它们完全是分开的。

vm.$onInit = function() {
    ....
    ....
    //Get all the items only once during initialization
    ds.getAllItems().then(function(result){
      vm.items = result;
     },function(error){
      vm.errorInApi = true;
    });
    .....
    .....
}
vm.getTimes = function(){
    .....
    .....
    HttpWrapper.send(url,{"operation":'GET'}).then(function(times){
                    .....
}

如果两个 API 都失败了,那么我只需要显示一个模式。

我可以将变量初始化为 true,并且在 API 失败时,我可以将其设为 false,然后仅显示模式。

但是要等多久才能完成所有 API?

【问题讨论】:

  • 通话是否同时进行?
  • 如果两者同时运行,你可以在 $q.all() 中换行
  • @guest271314 不首先调用 OnInit,然后在单击某些按钮时调用 getTimes。
  • 如果两个promise都失败了,你可以处理一个变量标志并用$watch监听。
  • @JesusCarrasco 我认为$q.all 将不起作用,因为一旦其中一个承诺被拒绝,就会调用拒绝回调并出现错误。

标签: javascript angularjs http promise


【解决方案1】:

嗯...只需反转承诺的极性并使用Promise.all()

Promise.all() 通常会在所有承诺解决后解决,因此一旦承诺被反转,一旦所有承诺都被拒绝,它就会解决......

var invert = p => new Promise((v, x) => p.then(x, v));

Promise.all([Promise.reject("Error 404"), Promise.reject("Error WTF")].map(invert))
       .then(v => console.log(v));

因此,根据@guest271314 的评论,我在银勺中扩展了解决方案,以展示如何将反转承诺应用于此任务。

var invert = p => new Promise((v, x) => p.then(x, v)),
    prps   = [Promise.reject("Error 404"), Promise.reject("Error WTF")]; // previously rejected promises

myButton.addEventListener('click', function(e){
                                     setTimeout(function(...p){
                                                  p.push(Promise.reject("Error in Click Event Listener"));
                                                  Promise.all(p.map(invert))
                                                         .then(r => results.textContent = r.reduce((r,nr) => r + " - " + nr));
                                                }, 200, ...prps);
                                   });
<button id="myButton">Check</button>
<p id="results"></p>

如果任何承诺(包括先前获得的承诺或事件处理程序中的一次)得到解决,您将不会得到任何输出。

【讨论】:

  • "getTimes 在某些按钮点击时被调用"
  • @guest271314 所以..?
  • Answer 的代码在哪里执行评估事件处理程序中 Promise 值的任务?
  • @guest271314 一旦你知道诀窍,这是一项微不足道的工作。但我已经添加了。
【解决方案2】:

您可以使用Promise.all

首先你应该得到一个数组中的两个promise。为了实现这一点,如果您的两个函数返回它们创建的承诺,这可能会很有用:

vm.$onInit = function() {
    ....
    ....
    return ds.getAllItems().then(function(result){
      vm.items = result;
     },function(error){
      vm.errorInApi = true;
    });
}
vm.getTimes = function(){
    .....
    .....
    return HttpWrapper.send(url,{"operation":'GET'}).then(function(times){
                    .....
    });
}

然后将根据返回值构建数组:

var arr = [];
arr.push(vm.$onInit());
...
arr.push(vm.getTimes());

你在评论中写道getTimes“在某些按钮点击时被调用”,所以你会在那里进行第二次推送。

或者,也许你看到了另一种方法来将这些承诺放在一个数组中......你如何做并不重要,只要你实现了这一点。

然后(在该单击处理程序中)您需要检测两个承诺都被拒绝的情况。 Promise.all 可以做到,但是你需要翻转 promise 结果:

// Flip promises so that a rejected one is regarded as fulfilled and vice versa:
arr = arr.map(p => p.then(res => { throw res }).catch(err => err));
// Detect that all original promises rejected, i.e. that the new promises all fulfill.
Promise.all(arr).then(function() {
    // execute whatever you need to execute when both ajax calls failed
}).catch(err => err); // ignore

【讨论】:

  • "getTimes 在某些按钮点击时被调用"
  • 谢谢,@guest271314,我不认为这会改变我的答案,但我添加了该引用和关于在该场景中放置代码的位置的建议。
  • 如果一个承诺失败另一个不执行,这将不起作用。就像 StanislavKvitash 说的
  • 那不在我的更新中,它从一开始就在那里 ;-)
  • 我认为带有一些 var 和 watch 的控制器是更好的控制器,因为如果你将两个 Promise 链接起来,如果一个失败另一个将不会执行,甚至第一个不是,第二个是。这并不意味着全部被拒绝。
【解决方案3】:

您可以使用async/await.catch() 来确定拒绝Promises 的数量,如果数量等于N,则执行操作,其中N 是执行操作所需的拒绝Promise 值的数量。

正如@trincot 所提到的,一个先决条件是从函数中传递return Promise 和传递给.then() 的函数中的值return,以及从@987654332 传递给throwError() @或.then()的第二个参数处的函数见Why is value undefined at .then() chained to Promise?

const N = 2;

function onInit() {
  return Promise.resolve("resolved")
}

function getTimes() {
  return Promise.reject("rejected");
}

const first = onInit();

document.querySelector("button")
.onclick = async function() {
  let n = 0;
  const firstP = await first.catch(() => ++n);
  const secondP = await getTimes().catch(() => ++n);
  if (n === N) {
    // do stuff if `n` is equal to `N`
  } else {
    // do other stuff
    console.log(n, N)
  }
};
&lt;button&gt;click&lt;/button&gt;

【讨论】:

    猜你喜欢
    • 2016-10-16
    • 2017-06-17
    • 1970-01-01
    • 1970-01-01
    • 2015-04-24
    • 1970-01-01
    • 2022-11-06
    相关资源
    最近更新 更多