[RxJS] Build your own RxJS

JavaScript has multiple APIs that use callback functions that all do nearly the same thing with slight variations. Event listeners, array methods such as .forEach, promises, and NodeJS streams all are very close in the way they are written. Instead, in RxJS you'd unify all of these APIs under one abstraction.

 

Normal RxJS API:

复制代码
import { from } from "rxjs";
import { map, filter } from "rxjs/operators";

from([1, 2, 3, 4])
  .pipe(map(x => x * 2))
  .pipe(filter(x => x < 5))
  .subscribe(val => console.log(val)); 
// 2 
// 4
复制代码

 

We can build our own RxJS operator

First, Observable,

  it has API:

{
  subscribe() {}
  pipe() {}  
}

 

We can create a function call 'createObservable(subscribe)', take a subscribe function, return a subscribe and pipe function:

function createObservable(subscribe) {
  return {
    subscribe,
    pipe(operator) {
      return operator(this);
    }
  };
}

 

We can use it to create Observables:

复制代码
const numberObservable = createObservable(function(observer) {
  [10, 20, 30, 40].forEach(x => {
    observer.next(x);
  });

  observer.complete();
});

const clickObservable = createObservable(function(observer) {
  document.addEventListener("click", function(ev) {
    observer.next(ev);
  });
});
复制代码

 

 

Second, Observer: 

  Observer is easy, it takes a object which contains 'next', 'error', 'complete' functions:

复制代码
const observer = {
  next(x) {
    console.log(x);
  },
  error(err) {
    console.error(err);
  },
  complete() {
    console.log("DONE");
  }
};
复制代码

 

Third, Operator, map, filter:

map(fn)(observable)

filter(predFn)(observable)  

It is important to know that map & filter, those operator, takes an inputObservable and will return an outputObservable.

We subscribe inputObservable, and inputObserver, inside inputObserver, we call outputObserver which is passed in from the consumer.

复制代码
const map = fn => inputObservable => {
  const outputObservable = createObservable(function(outputObserver) {
    const observer = {
      next(x) {
        const res = fn(x);
        outputObserver.next(res);
      },
      error(err) {
        outputObserver.error(err);
      },
      complete() {
        outputObserver.complete();
      }
    };
    inputObservable.subscribe(observer);
  });

  return outputObservable;
};

const filter = fn => inputObservable => {
  const outputObservable = createObservable(function(outputObserver) {
    const observer = {
      next(x) {
        if (fn(x)) {
          outputObserver.next(x);
        }
      },
      error(err) {
        outputObserver.error(err);
      },
      complete() {
        outputObserver.complete();
      }
    };
    inputObservable.subscribe(observer);
  });

  return outputObservable;
};
复制代码

 

--

Full Code:

复制代码
function createObservable(subscribe) {
  return {
    subscribe,
    pipe(operator) {
      return operator(this);
    }
  };
}

const numberObservable = createObservable(function(observer) {
  [10, 20, 30, 40].forEach(x => {
    observer.next(x);
  });

  observer.complete();
});

const clickObservable = createObservable(function(observer) {
  document.addEventListener("click", function(ev) {
    observer.next(ev);
  });
});

const map = fn => inputObservable => {
  const outputObservable = createObservable(function(outputObserver) {
    const observer = {
      next(x) {
        const res = fn(x);
        outputObserver.next(res);
      },
      error(err) {
        outputObserver.error(err);
      },
      complete() {
        outputObserver.complete();
      }
    };
    inputObservable.subscribe(observer);
  });

  return outputObservable;
};

const filter = fn => inputObservable => {
  const outputObservable = createObservable(function(outputObserver) {
    const observer = {
      next(x) {
        if (fn(x)) {
          outputObserver.next(x);
        }
      },
      error(err) {
        outputObserver.error(err);
      },
      complete() {
        outputObserver.complete();
      }
    };
    inputObservable.subscribe(observer);
  });

  return outputObservable;
};

const observer = {
  next(x) {
    console.log(x);
  },
  error(err) {
    console.error(err);
  },
  complete() {
    console.log("DONE");
  }
};

numberObservable
  .pipe(map(x => x * 3))
  .pipe(map(x => x - 9))
  .subscribe(observer);

clickObservable
  .pipe(map(ev => [ev.clientX, ev.clientY]))
  .pipe(filter(([x, y]) => x < 200 && y < 200))
  .subscribe(observer);
复制代码

 

posted @   Zhentiw  阅读(333)  评论(0编辑  收藏  举报
编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
历史上的今天:
2018-04-06 [Preference] How to avoid Forced Synchronous Layout or FSL to improve site preference
2016-04-06 [Angular 2] Property Binding
2016-04-06 [Angular 2] Interpolation: check object exists
点击右上角即可分享
微信分享提示