js 最简单的发布订阅模式

let _subscriber: any;

function autorun(subscriber: Function) {
  _subscriber = subscriber;
  _subscriber();
  _subscriber = null;
}

class Observer {
  #list: Function[] = []; // 订阅者

  private get _last() {
    if (!this.#list.length) return null;
    return this.#list[this.#list.length - 1];
  }
  // 添加订阅者
  add() {
    if (this._last !== _subscriber) {
      this.#list.push(_subscriber);
    }
  }

  // 发布时,把订阅者挨着挨着call
  publish() {
    this.#list.forEach((it: any) => it());
  }
}

function observable(data: any) {
  const o: Map<string, Observer> = new Map();
  for (const key in data) {
    o.set(key, new Observer());
  }

  const proxy = new Proxy(data, {
    get(target: any, key: any) {
      if (_subscriber) o.get(key)!.add();
      return target[key];
    },
    set(target: any, key: any, value: any, receiver: any) {
      if (value === target[key]) return false;
      target[key] = value;
      o.get(key)!.publish();
      return true;
    },
  });
  return proxy;
}

const obj = observable({ name: "ajanuw", data: "..." });

autorun(() => {
  console.log(obj.name);
  console.log("hello " + obj.name + obj.data);
});

setTimeout(() => {
  obj.name = "suou";
}, 1000);

setTimeout(() => {
  obj.data = "......";
}, 2000);

执行后:

λ ts-node index.ts
ajanuw
hello ajanuw...
suou
hello suou...
suou
hello suou......
posted @ 2020-04-04 18:28  Ajanuw  阅读(...)  评论(...编辑  收藏