[Javascript] Write Observable

发布时间 2023-09-05 21:02:29作者: Zhentiw
function Observable(forEach) {
  this._forEach = forEach;
}

Observable.prototype = {
  forEach: function (onNext, onError, onCompleted) {
    if (typeof onNext === "function") {
      return this._forEach({
        onNext,
        onError: onError || function () {},
        onCompleted: onCompleted || function () {},
      });
    } else {
      return this._forEach(onNext);
    }
  },
  map: function (transformer) {
    const self = this;
    return new Observable(function forEach(observer) {
      return self.forEach(
        (data) => {
          observer.onNext(transformer(data));
        },
        (e) => {
          observer.onError(e);
        },
        () => {
          observer.onCompleted();
        }
      );
    });
  },
  filter: function (preditionFn) {
    const self = this;
    return new Observable(function forEach(observer) {
      return self.forEach(
        (data) => {
          if (preditionFn(data)) {
            observer.onNext(data);
          }
        },
        (e) => {
          observer.onError(e);
        },
        () => {
          observer.onCompleted();
        }
      );
    });
  },
  take: function (maxCount) {
    const self = this;
    let count = 0;
    return new Observable(function forEach(observer) {
      return self.forEach(
        (data) => {
          const sub = observer.onNext(data);
          count++;
          if (count === maxCount) {
            observer.onCompleted();
            sub.dispose();
          }

          return sub;
        },
        (e) => {
          observer.onError(e);
        },
        () => {
          observer.onCompleted();
        }
      );
    });
  },
};

Observable.fromEvent = function (dom, eventName) {
  return new Observable(function forEach(observer) {
    const handler = (e) => observer.onNext(e);
    dom.addEventListener(eventName, handler);

    return {
      dispose: () => {
        dom.removeEventListener(eventName, handler);
      },
    };
  });
};

Observable.fromObservations = function (obj) {
  return new Observable(function forEach(observer) {
    const handler = (e) => observer.onNext(e);
    Object?.observe?.(obj, handler);
    return {
      dispose: () => {
        Object?.unobserve?.(obj, handler);
      },
    };
  });
};