【问题标题】:callback at the end of a loop in typescript打字稿循环结束时的回调
【发布时间】:2018-09-08 13:33:19
【问题描述】:

我对这段代码感到绝望。

getSumOfSpecificDayWeek(daysMonth: any, callback: any){
    var data = [];
    var that = this;
    daysMonth.forEach(function(day){
      that.statsService.getData(that.userid, day).subscribe(async (res: any) => {
        data = JSON.parse(JSON.stringify(res));
        console.log(that.data);
        that.data = that.data.map( function(v, i) {
          return v + data[i];
        });
      });
    });
    callback("this should be at the end");
  }

我正在做的是从服务器获取数组并将其汇总到每个组件的 that.data 中,这工作正常,但最后我想平均结果,此时我正在只是调用回调来显示一条消息以检查它是否最终发生,但没有,在循环开始求和之前显示“this should be at the end”。

  mycallback(arg: any){
    console.log(arg);
  }

这是对方法的主要调用

this.getSumOfSpecificDayWeek(daysMonth, this.mycallback);

【问题讨论】:

    标签: javascript angular typescript


    【解决方案1】:

    所以,遗憾的是,这种事情在 Javascript 中有点令人困惑。这将在后台触发对daysMonth 中所有内容的请求,然后调用您的回调。您之前触发的异步请求将在某个时候完成。

    最终,您需要做的是检测何时完成所有工作,然后触发您的回调。看看这样的东西:

    var numDone = 0;
    
    daysMonth.forEach(function(day){
      that.statsService.getData(that.userid, day).subscribe(async (res: any) => {
        numDone++;
    
        data = JSON.parse(JSON.stringify(res));
        console.log(that.data);
        that.data = that.data.map( function(v, i) {
          return v + data[i];
        });
    
        if(numDone == daysMonth.length) {
          callback("All done!")
        }
      });
    });
    

    实际上,我们可以在getData() 回调中做一些工作,如果我们是最后一个运行的东西,然后我们使用我们想要的任何数据调用外部回调。

    当然,这可能会变得混乱。 async 库很好地抽象了所有这些,因此您也可以将async.map 用于您的目的。

    【讨论】:

    • 也就是说,我没有注意到你已经在使用 RxJS。我肯定会改用@RolandRacz 的答案。
    • 您绝对应该使用@RolandRacz 答案,因为此版本不能很好地处理错误(并且不会调用您的回调)。在 Observable.forkJoin 中,您可以使用错误处理程序。
    【解决方案2】:

    更多的 RxJS,但更优雅的方式:

    getSumOfSpecificDayWeek(daysMonth: any, callback: any){
        var data = [];
        var that = this;
        let getCalls = []; // <--- This will contain all of your observables.
        daysMonth.forEach(function(day){
          const observable = that.statsService.getData(that.userid, day);
          getCalls.push(observable); // <--- Add the current observable to the array.
          observable.subscribe(async (res: any) => {
            data = JSON.parse(JSON.stringify(res));
            console.log(that.data);
            that.data = that.data.map( function(v, i) {
              return v + data[i];
            });
          });
        });
        // And here, you can use `callback`:
        Observable.forkJoin(...getCalls).subscribe(results => {
          callback("this should be at the end");
        });
    }
    

    【讨论】:

    • 这是要走的路。即使我建议将 that.statsService.getData(that.userid, day) 分配给一个变量,并将这个变量推送到数组中并在其上调用 subscribe。它看起来比 getCalls$[getCalls$.length - 1]
    • 变量名后面的 $ 也有原因/指南吗?实际上从来没有这样,我只是好奇:D
    • @NicolasGehlert 你完全正确,我编辑了我的答案。 :)
    • 没有关于$的官方指南,但是很多人用它来表示一个Observable变量。 (stackoverflow.com/questions/37671700/…) 虽然这是一个 Observable 数组,但也许这不是必需的。
    • 不会调用 api 两次,因为您在 foreach 方法中订阅了两次,在 forkjoin 期间订阅了一次。
    【解决方案3】:

    你需要用另一种方式管理 observable

    你需要执行一个异步操作数组,然后执行一个回调函数

    你的代码应该是这样的

    getSumOfSpecificDayWeek(daysMonth: any, callback: any){
        var data = [];
        var that = this;
        Observable.mergeArray(daysMonth.map(day=> that.statsService.getData(that.userid, day)).subscribe((arrOfResponses)=>{
    
    // do your job with the data 
      callback("this should be at the end"); })
    
    
      }
    

    【讨论】:

      猜你喜欢
      • 2020-06-01
      • 1970-01-01
      • 2017-10-21
      • 1970-01-01
      • 1970-01-01
      • 2013-10-29
      • 2013-12-24
      • 2019-04-05
      • 2017-04-21
      相关资源
      最近更新 更多