Implementando concat para concatenar observables

En los post anteriores tuvimos un acercamiento a la implementación del operador filter, map y of en observables, lo implementamos desde cero similarmente a como lo hace RX.js para entender un poco más la filosofía y el funcionamiento interno. En este post vamos a implementar una función que nos permita transformar distintos observables en uno solo concatenándolos. Esto puede resultar particularmente útil cuando quieres combinar datos que vienen desde una petición HTTP (FromEvent), con datos que tienes en arreglos o variables. Veamos un ejemplo:

  • js
1
2
3
4
const sourceOne = Observable.fromEvent(/** Algo que nos dé 1, 2, 3 por ejemplo*/);
const sourceTwo = of(4, 5, 6);
const fuenteDeLaVerdad = Observable.concat(sourceOne, sourceTwo);
fuenteDeLaVerdad.subscribe(/** lo que queramos hacer aquí*/);

En este ejemplo queremos combinar datos provenientes de una fuente dinámica con una fuente de datos estática, pero fácilmente podríamos combinar ambas fuentes estáticas o fuentes dinámicas, sin embargo el objetivo es claro, como podemos combinar dos observables. Veamos entonces, necesitamos que sea un método estático que me genere un nuevo observable a partir de los dos observables que reciba como parámetro. Por tanto un primer esqueleto podría ser algo similar a esto. (Recuerda que estamos bajo ES6 y una clase llamada Observable).

  • js
1
2
3
4
5
6
7
8
9
10
11
class Observable {
// ...
static concat(...observables) {
return new Observable(
function subscribe(observer) {
// Aquí implementaremos la combinación
}
);
}
//...
}

Bien, empecemos primero a desentrañar como estamos recibiendo los observables, como verás estamos usando spread operator para recibir tantos observables como queramos, (Acasó dije que solo se podían dos), esto …observables, nos permitirá poder combinar tantos como podamos y adicionalmente nos dará control sobre ellos. Lo primero entonces que necesitamos es poderlos dividir y tomar el primero de los observables, esto lo hacemos mediante dos funciones estándar para arreglos:

  • js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let myObservables = observables.slice();
let currentObservable = myObservables.shift();

const sourceOne = Observable.fromEvent(/** Algo que nos dé 1, 2, 3 por ejemplo*/);
const sourceTwo = of(4, 5, 6);
const fuenteDeLaVerdad = Observable.concat(sourceOne, sourceTwo);
//...
static concat(...observables) {
return new Observable(
function subscribe(observer) {
let myObservables = observables.slice();
let currentObservable = myObservables.shift();
// En currentObservable tendriamos sourceOne
}
);
}
//...

Bien, ahora solo necesitamos iterar sobre todos los elementos de nuestro observable y posteriormente cuando se acaben los elementos de este observable precipitarnos con el siguiente hasta que ya no queden más observables. Vamos usar recursividad esta vez porque nos permitirá implementar la misma lógica a través de los observables.

  • js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
static concat(...observables) {
return new Observable(function subscribe(observer) {
let myObservables = observables.slice();
let sub = null;
let processObservable = () => {
if (myObservables.length === 0) {
observer.complete();
} else {
let observable = myObservables.shift(); //Take the next observable in the params.sub = observable.subscribe({
next(v) {
observer.next(v);
},
error(err) {
observer.error(err);
sub.unsubscribe();
},
complete() {
processObservable();
}
});
}
};
processObservable();
return {
sub
};
});
}

Como verás solo existe una maneras de salir del primer observable al segundo, que se acaben los datos de dicho observable para lo cual volvemos a llamar la función processObservable y tomamos el siguiente observable de la lista. Si hay un error lo que hacemos inmediatamente es suspender todo el proceso de concatenación si bien en el bloque de código que te muestro arriba esta diseñado de esta manera, también podría haber una variación que podemos programar, para la cual simplemente podemos decirle que continue con el siguiente observable. Es decir:

  • js
1
2
3
4
5
6
7
8
//...
error(err) {
observer.error(err);
sub.unsubscribe();
// Si falla algo con un observable pasamos al siguiente
processObservable();
},
//...

Finalmente aquí está el ejemplo completo con la implementación de of y nuestro nuevo operador concat:

https://codepen.io/seagomezar/pen/EpOyRj

Eso es todo, espero que este post te sea de utilidad y lo puedas aplicar a algún proyecto que tengas en mente y que simplemente te haya ayudado a entender la naturaleza de los operadores sobre observables. déjame un comentario si lograste implementarlo, si quieres añadir alguna otra funcionalidad o si tienes alguna duda no dudes en dejarme un comentario en la parte de abajo, recuerda que si te gustó también puedes compartir usando los links a las redes sociales en la parte de abajo.

Copyrights © 2018 Sebastian Gomez. All Rights Reserved.

Sobre mí

sebastianMi nombre es Sebastián Gómez, soy ingeniero de sistemas e Informática y Magister en Ingeniería de Sistemas de la Universidad Nacional de Colombia.

Actualmente trabajo en Globant como Web UI Developer con énfasis en aplicaciones híbridas y cross compiladas. Soy el organizador del Google Developers Group de Medellín, así que contactame si quieres dar alguna charla o participar actuamente de esta comunidad.

He participado en una Startup Colombiana llamada SponzorMe al lado de Carlos Rojas y fuí participante de Startup Chile a pesar de no haber continuado con esta startup me apasiona el emprendimiento y me gusta aconsejar y ayudar startups como mentor técnico. También he trabajado en empresas Americanas como StudioHyperset en Estados Unidos y para Measured Medium. Mi interés y mi experiencia es el desarrollo de web y móvil full stack como Front-end con Javascript. Me apasiona desarrollar software, escribir código y enseñar lo que aprendo día a día.

También he trabajado como profesor en diferentes universidades en Medellín Colombia, con tematicas relacionadas con la Inteligencia Artificial, Bases de datos, programación orientada a objetos, minería de datos, desarrollo de software, desarrollo móvil y desarrollo web.

Me encanta escribir código rápido y prototipar de una manera accelerada si quieres ver que hago día a día puedes darle un vistazo a mi codepen:  https://codepen.io/seagomezar/.

Todos los días trato de crear o participar en proyectos, la mayoría open source, así que puede chequear mi GitHub:  https://github.com/seagomezar.

Mi áreas de investigación académica son: Ingeniería de software, Ingeniería de requisitos, procesamiento del lenguaje natural, Ontologías, Bases De Datos,  Machine Learning, Seguimiento de trayectorias y Modelamiento matemático de formaciones.

Estas son algunas de mis publicaciones académicas mas recientes: