【问题标题】:How do I cancel a Promise.all() in Angular 2?如何在 Angular 2 中取消 Promise.all()?
【发布时间】:2017-05-21 12:31:51
【问题描述】:

我目前有一个注册过程,并且在每次下一次单击时都会生成一个 Promise.all(),这会调用很多 http 请求。如果客户端非常快速地通过(非常快地按下下一个按钮)所有的 http 请求都会建立起来,它会弄乱我的应用程序。

有没有办法可以取消 Promise.all(),这样如果他们点击下一步并且之前的 Promise.all() 仍在运行,我可以取消它?

【问题讨论】:

  • 承诺不可取消。有一个规范正在制作它们,但它的工作被停止了。
  • @toskv 所以,promise 是不可取消的,但是使 promises 可取消的规范本身显然是可取消的。
  • @JeffBowman 很遗憾它是可以取消的。 :(
  • @georgej 你能澄清一下承诺是如何搞砸你的应用程序的吗?

标签: javascript angular typescript promise


【解决方案1】:

您可以等待承诺完成,但不能取消。

您可以禁用以下下一步按钮,直到它们全部完成。

<button [disabled]="completed">Next</button>

【讨论】:

    【解决方案2】:

    我会使用 observables,switchMapdebounceTime,类似

    export class MyComponent implements OnInit {
      actions: Observable<any[]>;
      private signals = new Subject<string>();
      constructor() {}
    
      submit(signal: string): void {
        this.signals.next(signal);
      }
    
      ngOnInit(): void {
        this.actions = this.signals
          .debounceTime(300)        
          .distinctUntilChanged()
          .switchMap(signal => {
             // make http calls with the signal e.g
             // return this.service.getAction(signal)
          })
          .catch(error => {
            // handle error
          });
      }
    }
    

    这是基于https://angular.io/docs/ts/latest/tutorial/toh-pt6.html#!#-_observable-s

    switchMap 的一个好处是,如果另一个信号通过,它将取消任何飞行中的 http 请求。话虽这么说,如果您的服务器不处理取消的请求,那也无济于事。

    【讨论】:

    • 这个解决方案不依赖于硬编码的.debounceTime(300) 是任何被去抖动的合适模型吗?在 OP 的情况下,如果他的 $q.all() 花费超过 300 毫秒的时间来解决怎么办?
    • 嗯我可能误解了这个问题,我认为 OP 想减少应用服务器的工作量,即后端。为什么多个 http 请求会弄乱前端 Angular 应用程序?
    • 我想您可能会从问题的第一段中理解这一点,但不是第二段。再读一读,看看你是否同意。
    • 我还是不明白:/ 我已经要求 OP 澄清
    • 好主意。让我们看看他怎么说。
    【解决方案3】:

    假设“取消 Promise.all()”意味着“确保 Promise.all() 返回的承诺不遵循其成功路径” ....

    承诺不可取消,但基于模式的解决方案可用。

    这里的概念相当简单。本质上,在每批 Promise 中,您可以包含一个 Promise:

    • 如果原始批次成功将解决
    • 将在创建下一批时被拒绝。

    这是一场善与恶的竞赛。

    困难的部分是使“超级聚合”对结果透明。

    这是一种写法 - 可能不是最简洁的 - 有人可能会发现更好的方法。

    function BatchCanceller() {
        // Return a function, which accepts an array of promises and returns an aggregated promise.
        // Use the returned function like $q.all().
        var dfrd;
        return function(promises) {
            if(dfrd) {
                dfrd.reject(new Error('cancelled')); // reject previous batch
            }
            dfrd = $q.defer();
            // Preparation; ensure that `promises`, if all are successful, resolve `dfrd`.
            $q.all(promises).then(dfrd.resolve);
            // Now include `dfrd` in a super-aggregation of `promises`
            return $q.all(promises.concat(dfrd.promise)) // Will the aggregated `promises` resolve before another batch causes `dfrd.reject()`?
            .then(function(results) {
                // Yay! the aggregated `promises` won out.
                return results.splice(0, results.length-1); // remove the unwanted extra result.
            }); // no need to handle error here
        };
    }
    
    var batchCanceller = new BatchCanceller();
    
    var promises = [/* whatever */];
    batchCanceller(promises).then(function(results) {
        console.log(results);
    }).catch(function(error) {
        console.log(error); // message is "cancelled" if another `batchCanceller(promises)` is executed before the previous one resolves.
    });
    

    在实践中,您可能会选择将 BatchCanceller() 表示为 Angular 工厂。

    【讨论】:

      猜你喜欢
      • 2016-07-29
      • 2016-07-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-01
      • 2020-09-15
      • 2017-11-12
      相关资源
      最近更新 更多