smac89
6/29/2017 - 2:15 AM

Chained callbacks

Chained callbacks

interface ChainedCallback {
    (): void;
}

class ChainedCallback {
    private chain: Callback[];

    public static fromCallbacks(...cbs: Callback[]): ChainedCallback {
        let chained = new ChainedCallback();
        cbs.forEach(chained.attach);
        return chained;
    }

    public asPromise(): Promise<Error> {
        return new Promise((resolve, reject) => {
            try {
                this();
                resolve(null);
            } catch (e) {
                reject(e);
            }
        });
    }

    public attach(cb: Callback): ChainedCallback {
        this.chain.push(cb);
        return this;
    }

    public exec(): void {
        if (this.chain.length) {
            this.chain.first()();
        }
    }

    public execAll(): void {
        this.chain.forEach(cb => cb());
    }

    public execDetach(): ChainedCallback {
        if (this.chain.length) {
            this.chain.pop()();
        }
        return this;
    }

    public detach(): Callback {
        if (this.chain.length) {
            return this.chain.pop();
        }
        return null;
    }

    public detachAll(): void {
        // https://stackoverflow.com/a/1232046/2089675
        this.chain.splice(0, this.chain.length);
    }

    public execDetachAll(): void {
        // https://stackoverflow.com/a/1232046/2089675
        this.chain.splice(0, this.chain.length)
            .forEach(cb => cb());
    }

    constructor() {
        Object.assign(this.execAll, this);
    }
}