vendredi 15 mai 2020

How to emit event upward on the dependency tree in Javascript?

I have a simple StopWatchController that creates and controls multiple StopWatch objects (the dependencies).

When an event triggers inside each StopWatch (their clock reaches a certain date), the StopWatch needs to notify the StopWatchController. Then the controller needs to get some value from all the StopWatch (their getState() output) and print it. (in a realife scenario, this happen on the server side, when an event happens inside each worker, the controller needs to notify the client)

My first attempt:

My first attempt involves Circular dependencie. More specifically, the controllers depends on the stopwatches but I am also passing the controller to each instance of the StopWatch. (in their constructor, I pass this -> referring to the StopWatchController )

class StopWatch {
    private eventDate: number;
    private master: StopWatchController;
    private currentTime = 0;
    private trigger = false;

    constructor(eventDate: number, master: StopWatchController) {
        this.eventDate = eventDate;
        this.master = master;
    }

    start() {
        setInterval(() => {
            if (this.currentTime === this.eventDate) {
                this.trigger = true;
                this.emitEvent();
            }
            this.currentTime++;
        }, 1000);
    }

    private emitEvent() {
        this.master.onTrigger();
    }

    getState() {
        return [this.currentTime, this.trigger];
    }
}

class StopWatchController {
    private stopWatches: StopWatch[] = [];

    createSlaves(count: number) {
        for (let i = 0; i < count; i++) {
            const slave = new StopWatch(this.getRandomDate(), this);
            this.stopWatches.push(slave);
        }
    }

    start() {
        this.stopWatches.forEach((s => s.start()));
    }

    private getRandomDate() {
        return Math.floor(Math.random() * 10) + 1;
    }

    onTrigger() {
        console.log('One of the stopwatch has triggered!');
        console.log('Summary is:', this.getAllStopWatchState());
    }

    private getAllStopWatchState() {
        return this.stopWatches.map(s => s.getState());
    }
}

function main() {
    const master = new StopWatchController();
    master.createSlaves(10);
    master.start();
}

main();

My Second attempt:

My second attempt prevents circular dependency issue by passing an event handler instead of the whole class to each instance of the StopWatch. In my case, the event handler is a callback function. ( instead of this , I pass this.onTrigger.bind(this)

class StopWatch {
    private eventDate: number;
    private currentTime = 0;
    private onTrigger: () => void;
    private trigger = false;

    constructor(eventDate: number, onTrigger: () => void) {
        this.eventDate = eventDate;
        this.onTrigger = onTrigger;
    }

    start() {
        setInterval(() => {
            if (this.currentTime === this.eventDate) {
                this.trigger = true
                this.emitEvent();
            }
            this.currentTime++;
        }, 1000);
    }

    private emitEvent() {
        this.onTrigger();
    }

    getState() {
        return [this.currentTime, this.trigger];
    }
}

class StopWatchController {
    private stopWatches: StopWatch[] = [];

    createSlaves(count: number) {
        for (let i = 0; i < count; i++) {
            const slave = new StopWatch(this.getRandomDate(), this.onTrigger.bind(this));
            this.stopWatches.push(slave);
        }
    }

    start() {
        this.stopWatches.forEach((s => s.start()));
    }

    private getRandomDate() {
        return Math.floor(Math.random() * 10) + 1;
    }

    onTrigger() {
        console.log('One of the stopwatch has triggered!');
        console.log('Summary is:', this.getAllStopWatchState());
    }

    private getAllStopWatchState() {
        return this.stopWatches.map(s => s.getState());
    }
}

function main() {
    const master = new StopWatchController();
    master.createSlaves(10);
    master.start();
}

main();

My question

I have read several posts on StackOverFlow and most people highly recommend preventing Circular dependencies as much as possible.

Is there a way to pass the event better than my second attempt?

I am looking for a solution that is at the same time Easy to unit-test, more maintainable` and more scalable.

Aucun commentaire:

Enregistrer un commentaire