Created
April 14, 2021 04:41
-
-
Save mizchi/050b2442ba04df3f462d1c0230a664dd to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type EventBase = { | |
__uid?: string; | |
__ts?: number; | |
}; | |
type PubSub<Event> = { | |
dispatch: (ev: Event) => void; | |
subscribe: (fn: (ev: Event) => void) => void; | |
}; | |
type Store<Event extends EventBase> = PubSub<Event> & { | |
createContext(id: string): ContextStore<Event>; | |
history: Event[]; | |
}; | |
type ContextStore<Event extends EventBase> = PubSub<Event> & { | |
start(): void; | |
}; | |
function createStore<Event extends EventBase>(): Store<Event> { | |
const history: Event[] = []; | |
const handlers: Set<(ev: Event) => void> = new Set(); | |
const dispatch = (ev: Event) => { | |
ev.__ts = Date.now(); | |
if (ev.__uid == null) { | |
history.push(ev); | |
} | |
handlers.forEach((fn) => { | |
fn(ev); | |
}); | |
}; | |
const subscribe = (handler: (ev: Event) => void) => { | |
handlers.add(handler); | |
}; | |
function createContext(uid: string) { | |
let ready = false; | |
let localQueue: Array<Event> = []; | |
return { | |
dispatch: (ev: Event) => { | |
if (!ready) { | |
localQueue.push(ev); | |
} else { | |
dispatch(ev); | |
} | |
}, | |
subscribe: (handler: (ev: Event) => void) => { | |
subscribe((ev) => { | |
if (ev.__uid && uid !== ev.__uid) { | |
return; | |
} | |
handler(ev); | |
}); | |
}, | |
start() { | |
ready = true; | |
// local dispatch | |
history.forEach((ev) => { | |
dispatch({ ...ev, __uid: uid }); | |
}); | |
// distribute local events for all | |
localQueue.forEach((item) => dispatch(item)); | |
}, | |
}; | |
} | |
return { | |
dispatch, | |
subscribe, | |
createContext, | |
history, | |
}; | |
} | |
type MyEvent = EventBase & { | |
type: string; | |
}; | |
it("xxx", async () => { | |
let p1c = 0; | |
let p2c = 0; | |
let p3c_lazy = 0; | |
const store = createStore<MyEvent>(); | |
function p1(store: ContextStore<MyEvent>) { | |
store.dispatch({ type: "xxx" }); | |
store.subscribe((ev) => { | |
console.log("[p1] received", ev); | |
if (ev.type === "yyy") { | |
p1c++; | |
} | |
}); | |
} | |
function p2(store: ContextStore<MyEvent>) { | |
store.dispatch({ type: "yyy" }); | |
store.subscribe((ev) => { | |
console.log("[p2] received", ev); | |
if (ev.type === "yyy") { | |
p2c++; | |
} | |
}); | |
} | |
async function p3(store: ContextStore<MyEvent>) { | |
await new Promise((r) => setTimeout(r, 100)); | |
store.dispatch({ type: "zzz" }); | |
return store.subscribe((ev) => { | |
if (ev.type === "yyy") { | |
p3c_lazy++; | |
} | |
}); | |
} | |
await Promise.all( | |
[p1, p2, p3].map(async (fn) => { | |
const uid = Math.random().toString(32).substr(2); | |
const ctx = store.createContext(uid); | |
await fn(ctx); | |
ctx.start(); | |
}) | |
); | |
expect(p1c).toBe(1); | |
expect(p2c).toBe(1); | |
expect(p3c_lazy).toBe(1); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment