Skip to content

Latest commit

 

History

History
109 lines (81 loc) · 3.13 KB

File metadata and controls

109 lines (81 loc) · 3.13 KB

74. implement Observable Transformation Operators

Problem

https://bigfrontend.dev/problem/implement-Observable-transformation-operators

Problem Description

This is a follow-up on 57. create an Observable.

There are a lot of operators for Observable, if we think of Observable as event stream, then modifying the stream is a common task, transformation operators are useful at this.

In this problem, you are asked to implement map(), as the name indicates, it maps the value to another value thus creating a new event stream.

Here is an example.

const source = Observable.from([1, 2, 3]);

map((x) => x * x)(source) // this transformer doubles numbers and create a new stream
  .subscribe(console.log);
// 1
// 4
// 9

Observable has pipe() method which could make this more readable.

const source = Observable.from([1, 2, 3]);

source.pipe(map((x) => x * x)).subscribe(console.log);
// 1
// 4
// 9

Note Observable is already given for you, no need to create it.

Understanding the problem

I am asked to write a function called map(). It should take in a function that is going to be called on each value emitted by the source Observable. It should return a function that will receive the source Observable and returns the transformed Observable. The class Observable is provided for me.

Approach

In the map function, first I need to return a function which takes in an observable as source and returns the transformed observable.

function map(transform) {
  return (sourceObservable) => {
    // return transformedObservable
  };
}

In a observable, the value that the observable emits is going to be passed to subscriber.next(value). Therefore, in order to apply the transform function on each value the source observable emits, I need to wrap the subscriber.next(value):

// store the original subscriber.next
subscriber.next = (value) => {
  value = transform(value);
  // invoke the original subscriber.next passing
  // in the transformed value.
};

That means, I need to create a new Observable instance; wrap the subscriber.next(value) in the setup of the new Observable and invoke the source observable subscriber passing in the modified subscriber.

return (sourceObservable) => {
  const transformedObservable = new Observable((subscriber) => {
    subscriber.next = (value) => {
      // ...
    };
    sourceObservable.subscribe(subscriber);
  });
  // return transformedObservable
};

Return the transformed observable at the end.

Solution

/**
 * @param {any} input
 * @return {(observable: Observable) => Observable}
 * returns a function which transform Observable
 */
function map(transform) {
  return (source) => {
    return new Observable((subscriber) => {
      const originalNext = subscriber.next;
      subscriber.next = (value) => {
        const newValue = transform(value);
        originalNext.call(subscriber, newValue);
      };
      source.subscribe(subscriber);
    });
  };
}