61

I am using the SQLStorage from the Ionic platform. The remove function returns a promise. In my code I need to remove multiple values. When these are all finished I need to execute some code.

How can I wait for all of these and then execute a callback function?

Code:

removeAll() {    
  this.storage.remove(key1);
  this.storage.remove(key2);
  this.storage.remove(key3);    
}

Nesting all is a bad practise so I am looking for a decent solution :)

removeAll() {
  return this.storage.remove(key1).then(() => {
    this.storage.remove(key2).then(() => {
      this.storage.remove(key3);        
    });
  });
};
trincot
  • 317,000
  • 35
  • 244
  • 286
Bas van Dijk
  • 9,933
  • 10
  • 55
  • 91

6 Answers6

97

You can use

removeAll() {
  Promise.all([
    this.storage.remove(key1),
    this.storage.remove(key2),
    this.storage.remove(key3),
  ]).then(value => doSomething());

See also https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • 8
    I would add that if any of these promises rejects, `Promise.all` will immediately reject (whether or not the rest have finished) and the `then` will be skipped. If you need to run `doSomething()` whether they succeed or they fail, you need to `catch` each of then individually to return a `Promise.resolve()`. – Manu Valdés Jun 15 '16 at 19:11
  • 1
    With `Promise.all()`, will they be excecuted one after each other, or all at once ? – Robouste Aug 31 '17 at 11:02
  • 1
    All calls are executed immediately, then `Promise.all()` just waits for all these promises to complete before it completes itself. This is not a `Promise.all` feature. With this code `Promise.all([ this.storage.remove(key1),`, ...]);` `this.storage.remove(key1)` is called and only the return value (a `Promise`) is added to the array that is passed to `Promise.all(...)` – Günter Zöchbauer Aug 31 '17 at 11:07
38

You could use Observable.forkJoin from rxjs by providing an array of all the observables/promises. This needs to be done before performing the operation. It's similar to Angular 1's $q.all.

rxjs version <= 6

Observable.forkJoin([
   this.storage.remove(key1), 
   this.storage.remove(key2),
   this.storage.remove(key3)
])
.subscribe(t=> {
    var firstResult = t[0];
    var secondResult = t[1];
});

rxjs version > 6

import {forkJoin} from 'rxjs';

forkJoin([
   this.storage.remove(key1), 
   this.storage.remove(key2),
   this.storage.remove(key3)
])
.subscribe(t=> {
    var firstResult = t[0];
    var secondResult = t[1];
});
tobias47n9e
  • 2,233
  • 3
  • 28
  • 54
Pankaj Parkar
  • 134,766
  • 23
  • 234
  • 299
5

On rxjs version > 6 You can do something like this:

import {forkJoin} from 'rxjs';

and do instead of Observable.forkJoin this:

forkJoin([
  this.service1.get(),
  this.service2.get()
]).subscribe(data => {
  this.data1= data[0];
  this.data2 = data[1];
4

I'm not familiar with IONIC, but assuming that storage.remove is returning a promise I would suggest you to use forkJoin operator from observables.

forkJoin takes an array of observables and awaits the execution of all items.

Just notice that I had to create 3 new observables from each promise returned by the .remove method.

Observable.forkJoin([
   Observable.fromPromise(this.storage.remove(key1)), 
   Observable.fromPromise(this.storage.remove(key2)),
   Observable.fromPromise(this.storage.remove(key3))
])
.subscribe(data => {
    console.log(data[0]);
    console.log(data[1]);
    console.log(data[2]);
});
Spikolynn
  • 4,067
  • 2
  • 37
  • 44
Daniel Pliscki
  • 1,913
  • 16
  • 24
3

Use Promise.all():

The Promise.all(iterable) method returns a promise that resolves when all of the promises in the iterable argument have resolved, or rejects with the reason of the first passed promise that rejects.

Syntax

Promise.all(iterable);

Parameters

iterable

An iterable object, such as an Array. See iterable.

Community
  • 1
  • 1
JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
3

use Promise.all for Promisses and Observable.forkJoin for Observables

as the question is about angular(2+) and you problably should have been using Observable instead of promises. i`ll add a GET example that worked for me:

import {Observable} from 'rxjs/Rx';
    
Observable.forkJoin(
      this._dataService.getOne().map(one => this.one = one),
      this._dataService.getTwo().map(two => this.two = two),
      this._dataService.getN().map(n => this.n = n),
     )
    ).subscribe(res => this.doSomethingElse(this.one, this.two, this.n)); 

note the use one .map() to handle the response rather than .subscribe()

Rikin Patel
  • 8,848
  • 7
  • 70
  • 78