const TimedPromise = function(resolve, reject, always, timeoutMs) {
    let timeout, resolved = false;

    const cancelTimeout = () => {
        if(timeout === undefined) {
            clearTimeout(timeout);
            timeout = undefined;
        }
    };

    const doResolve = (...args) => {
        if(resolved) return;
        resolved = true;

        cancelTimeout();
        reject = undefined;

        if(typeof resolve === 'function')
            resolve(...args);
        if(typeof always === 'function')
            always();
    };

    const doReject = (...args) => {
        if(resolved) return;
        resolved = true;

        cancelTimeout();
        resolve = undefined;

        if(typeof reject === 'function')
            reject(...args);
        if(typeof always === 'function')
            always();
    };

    timeout = setTimeout(() => doReject('timeout'), timeoutMs);

    return {
        resolve: doResolve,
        reject: doReject,
        cancel: () => {
            if(timeout === undefined)
                return;
            doReject('timeout');
        },
    };
};
