DEV Community

Bukunmi Odugbesan
Bukunmi Odugbesan

Posted on

Coding Challenge Practice - Question 107

The task is to implement the Observable from.

The boilerplate code

function from(input) {
  // your code here
}
Enter fullscreen mode Exit fullscreen mode

from() creates an Observable from an array, an array-like object, a Promise, an iterable, or an observable-like object. It does not emit immediately and decides how to emit values based on the type of input.

If the input type is an observable-like object, the values flow directly to the new observer.

if (input && typeof input.subscribe === "function") {
  return new Observable(observer => input.subscribe(observer));
}
Enter fullscreen mode Exit fullscreen mode

If the input type is a promise, if it resolves, it emits one value and calls complete(). If it rejects, it calls error()

if (input && typeof input.then === "function") {
  return new Observable(observer => {
    let cancelled = false;

    input.then(
      value => {
        if (!cancelled) {
          observer.next(value);
          observer.complete && observer.complete();
        }
      },
      err => !cancelled && observer.error && observer.error(err)
    );

    return () => {
      cancelled = true;
    };
  });
}
Enter fullscreen mode Exit fullscreen mode

If the input type is iterable, each value is emitted via next in a synchronous loop. Call complete after iteration.

if (input && Symbol.iterator in Object(input)) {
  return new Observable(observer => {
    try {
      for (const item of input) {
        observer.next(item);
      }
      observer.complete && observer.complete();
    } catch (err) {
      observer.error && observer.error(err);
    }
  });
}
Enter fullscreen mode Exit fullscreen mode

If the input type is a non-iterable array-like object

  if (input && typeof input === "object" && typeof input.length === "number") {
  return new Observable(observer => {
    try {
      for (let i = 0; i < input.length; i++) {
        observer.next(input[i]);
      }
      observer.complete && observer.complete();
    } catch (err) {
      observer.error && observer.error(err);
    }
  });
}
Enter fullscreen mode Exit fullscreen mode

If the input is invalid, throw an error

throw new TypeError("Input type not supported");
Enter fullscreen mode Exit fullscreen mode

The final code

function from(input) {
  // your code here
  if(input && typeof input.subscribe === "function") {
    return new Observable(observer => input.subscribe(observer))
  }

  if(input && typeof input.then === "function") {
    return new Observable(observer => {
      let cancelled = false;

      input.then(
        value => {
          if(!cancelled) {
            observer.next(value);
            observer.complete && observer.complete()
          }
        },
        err => !cancelled && observer.error && observer.error(err)
      )
      return () => {
        cancelled = true;
      }
    })
  }
  if(input && Symbol.iterator in Object(input)) {
    return new Observable(observer => {
      try {
        for(const item of input) {
          observer.next(item);
        }
        observer.complete && observer.complete();
      } catch (err) {
        observer.error && observer.error(err);
      }
    })
  }
  if(input && typeof input === "object" && typeof input.length === "number") {
    return new Observable(observer => {
      try {
        for(let i = 0; i < input.length; i++) {
          observer.next(input[i]);
        }
        observer.complete && observer.complete()
      } catch (err) {
        observer.error && observer.error(err);
      }
    })
  }
  throw new TypeError("Input type not supported");
}
Enter fullscreen mode Exit fullscreen mode

That's all folks!

Top comments (0)