0

I would like to convert and replace all words in an array using a an object's method which returns an observable. I'm using bind based on this answer to pass the correct value.

When all subscriptions finish, I would like to call another function called task2(). How can I implement this?

for(let word in this.words){
    var i = Object.keys(this.words).indexOf(word);

    this.convertor.get(this.words[i].value).subscribe( function (i, result) {
    this.words[i].value = result; 
  }.bind(this, i));
}

//task2() <--------- when all subscribe functions finished
Community
  • 1
  • 1
Ari
  • 7,251
  • 11
  • 40
  • 70
  • Possible duplicate of [Promise.all behavior with RxJS Observables?](http://stackoverflow.com/questions/35608025/promise-all-behavior-with-rxjs-observables) – Simon H Jan 15 '17 at 19:39

2 Answers2

1

What type is this.words? If it's an array then it's way easier to loop on their items... you are doing something really strange there...

Also, consider using arrow functions to avoid using bind(this) everywhere. It helps on reading out the code.

You should rewrite your code by using forkJoin:

let streams = [];
for(let i = 0; i<this.words.length; i++){
    streams.push(this.convertor.get(this.words[i].value));
}

Rx.Observable.forkJoin(streams).subscribe((result) => {
    // Here result is an array with the results, and it's sorted properly (The first result is from the first stream, and so on).
    for(let i=0; i<result.length; i++) {
        this.words[i].value = result[i];
    }

    task2();
});
olivarra1
  • 3,269
  • 3
  • 23
  • 34
  • Nice suggestion! I just have one concern: how does the run time of this code compare to the case where bind is used. Seems like you first push everything in one array (streams). What if this array is too big? – Ari Jan 17 '17 at 02:03
  • @Ari `bind` internally returns a function that will set up `this` and pass in any parameters to the function you defined. Since we don't need any additional parameters using this solution, and `this` can be set up by using arrow functions, we just don't need it. I'm not too sure on the effect of using an array... Could be interesting to test/benchmark it. Having `.subscribe(` into a huge-repeating loop is not too good either. – olivarra1 Jan 17 '17 at 08:24
0

My template solution: generate function, which call another function only after N calls (like Promise.all)

Something like this:

  function onlyNthCall(callCount, callback)
    {
    var callIter = 0;
    return function()
      {
      callIter++;
      if(callIter === callCount) { callback(); }
      }
    }
var task2AfterLastCall = onlyNthCall(Object.keys(this.words).length, task2);

for(let word in this.words){
    var i = Object.keys(this.words).indexOf(word);

    this.convertor.get(this.words[i].value).subscribe( function (i, result) {
    this.words[i].value = result; 
    task2AfterLastCall();
  }.bind(this, i));
}
georgsh
  • 109
  • 5