Script Preparation code:
x
 
function LoopObservable() {
    const listeners = new Set();
    this.on = fn => listeners.add(fn);
    this.off = fn => listeners.delete(fn);
    this.clear = () => listeners.clear();
    // This has bad failure modes.
    this.send = function(...message) {
        for (let fn of listeners)
            fn(...message);
    };
};
function EventTargetObservable() {
    // Name is arbitrary because we're using a dedicated object.  Use a shorter
    // name for shorter lookup.
    const NAME = '.';
    const __ = new EventTarget()
    this.on = function(handler) {
        __.addEventListener(NAME, event => {
            handler(event.detail);
        });
    };
    this.off = function(handler) {
        __.removeEventListener(NAME, handler);
    };
    this.send = function(detail) {
        __.dispatchEvent(new CustomEvent(NAME, {
            detail
        }));
    };
}
function run_test(observable, handlers = 2, calls = 1000) {
    for (let i = 0; i < handlers; i++)
        observable.on(message => console.log(i, message));
    for (let i = 0; i < calls; i++)
        observable.send({
            type: "hello",
            i
        });
}
Tests:
  • loop observable

     
    run_test(new LoopObservable());
  • EventTarget observable

     
    run_test(new EventTargetObservable());
Rendered benchmark preparation results:

Suite status: <idle, ready to run>

Previous results

Experimental features:

  • Test case name Result
    loop observable
    EventTarget observable

    Fastest: N/A

    Slowest: N/A

Latest run results:
Run details: (Test run date: 4 years ago)
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.193 Safari/537.36
Chrome 86 on Mac OS X 10.15.7
View result in a separate tab
Test name Executions per second
loop observable 7.6 Ops/sec
EventTarget observable 5.6 Ops/sec