Estoy tratando de mejorar mi conocimiento de Angular2 migrando una aplicación actualmente escrita en Angular1/AngularJS.
Una característica en particular me tiene perplejo. Estoy tratando de replicar una función en la que una función de llamada espera para continuar hasta que la función a la que llama haya completado un ciclo de promesas. En AngularJS, la función a la que llamo se ve básicamente así:
this.processStuff = function( inputarray, parentnodeid ) { var promises = []; var _self = this; angular.forEach( inputarray , function( nodeid ) { switch ( parentnodeid ) { case 'AAA' : var component = _self.doMoreStuff( nodeid, parentnodeid ); break; case 'BBB' : var component = _self.doMoreStuff( nodeid, parentnodeid ); break; case 'CCC' : var component = _self.doMoreStuff( nodeid, parentnodeid ); break; default : var component = null; } promises.push( component ); }); return $q.all(promises); }; Contiene un bucle forEach que llama a otra función ( doMoreStuff ) que también devuelve una promesa y almacena todas esas promesas devueltas en una matriz.
Con AngularJS, cuando llamo a processStuff en otra función, puedo contar con que el sistema esperará hasta que se complete processStuff antes de ingresar el código en el bloque luego:
service.processStuff( arraying, parentidarg ) .then(function( data ) { ... La persona que llama de processStuff espera a que se completen todas las invocaciones de doMoreStuff hasta que la persona que llama de processStuff entra en su bloque then .
No estoy seguro de cómo lograr esto con Angular2 y Observables. Puedo ver en estas publicaciones que para imitar las promesas, los Observables básicamente solo usan subscribe() en lugar de then() :
Angular 1.x $q a Angular 2.0 beta
Pero, ¿cómo espero que se completen todas las invocaciones en el ciclo forEach antes de que mi aplicación pueda continuar?
He estado haciendo esto con forkJoin
import {Observable} from 'rxjs/Observable'; import 'rxjs/add/observable/forkJoin'; Observable.forkJoin( this.http.get('./friends.json').map((res: Response) => res.json()), this.http.get('./customer.json').map((res: Response) => res.json()) ) .subscribe(res => this.combined = {friends: res[0].friends, customer: res[1]});Más información aquí: http://www.syntaxsuccess.com/viewarticle/angular-2.0-and-http
En RxJS v6 y versiones posteriores, puede hacer esto de manera más elocuente con zip .
import { zip } from 'rxjs'; const promise1 = yourSvc.get(yourFavoriteAPI.endpoint1); const promise2 = yourSvc.get(yourFavoriteAPI.endpoint2); const promises = zip(promise1, promise2); promises.subscribe(([data1, data2]) => { console.log(data1); console.log(data2); }); Si bien el resultado es el mismo, creo que zip es preferible a forkJoin ya que zip es más universal y puede manejar nuevos valores de los observables.
Detalles de la documentación de rxjs :
El operador zip se suscribirá a todos los observables internos, esperando que cada uno emita un valor. Una vez que esto ocurra, se emitirán todos los valores con el índice correspondiente. Esto continuará hasta que se complete al menos un observable interno.