简体   繁体   中英

stop promises execution on certain time

function sleep(t) {
    return new Promise((resolve, reject) =>{
        setTimeout(() => {
            console.log('timeout!')
            return resolve({isTimeout: true})
        }, t);
    });
}

function thirdPartyFunction(t) { // thirdPartyFunction can't be edited
    return new Promise((resolve, reject) =>{
        setTimeout(() => {
            console.log('thirdPartyFunction completed!')
            return resolve({success: true})
        }, t);
    });
}

function main() {
    return new Promise(async(resolve, reject) => {
        try {
            let thirdPartyFunctionExecutionTime =  Math.floor(Math.random() * 10) + 1;
            thirdPartyFunction(thirdPartyFunctionExecutionTime * 1000, false).then( (r) => {
                console.log('should not execute this if thirdPartyFunctionExecutionTime > timeout') // only goal
                // other code which is not useful after timeout
            });

            const timeout = 3;
            console.log(`thirdPartyFunctionExecutionTime: ${thirdPartyFunctionExecutionTime}, timeout - ${timeout}`)
            await sleep(timeout * 1000, true);
            throw 'stop main()'
            // return
        } catch (error) {
            console.log('in catch')
            return;
        }
    })
}


main()

Timeout is fixed. thirdPartyFunctionExecutionTime might be very large (sometimes) in my actual case, say 30 secs. I don't want something to be running on background after timeout.

thirdPartyFunction promise function should stop execution on timeout.

FYI, here's a generic function to add a timeout with the option of cancelling. This can be used with any promise to add a timeout to it.

If the underlying asynchronous operation represented by the promise is cancellable, then you can supply a cancel function. If the async operation finishes first, this will clean up the timer for you automatically so it doesn't keep running.

// the main purpose of this class is so that callers can test
// to see if the reject reason is a TimeoutError vs. some other type of error
class TimeoutError extends Error {
    constructor(...args) {
        super(...args);
    }

}

// add a timeout to any promise
function addTimeout(promise, t, timeoutMsg = "timeout") {
    let timer;
    const timerPromise = new Promise((resolve, reject) => {
        timer = setTimeout(() => {
            timer = null;
            // if the promise has a .cancel() method, then call it
            if (typeof promise.cancel === "function") {
                try {
                    promise.cancel();
                } catch(e) {
                    console.log(e);
                }
            }
            reject(new TimeoutError(timeoutMsg));
        }, t)
    });
    // make sure the timer doesn't keep running if the promise finished first
    promise.finally(() => {
        if (timer) {
            clearTimeout(timer);
        }
    })
    return Promise.race([promise, timerPromise]);
}

And, you could then use this in your code like this:

function main() {
    addTimeout(thirdPartyFunction(...), 3000).then(result => {
        // thirdPartyFunction succeeded and timeout was not hit
        // use the result here
    }).catch(err => {
        console.log(err);
        // an error occurred here
        if (err instanceof TimeoutError) {
            // timeout
        } else {
            // other error
        }
    })
}

If your asynchronous operation has an ability to be cancelled if this operation times out, you could support that like this:

function main() {
    let p = thirdPartyFunction(...);
    p.cancel = function () {
        // cancel the thirdPartyFunction here (depends uponn the specific operation)
    }
    addTimeout(p, 3000).then(result => {
        // thirdPartyFunction succeeded and timeout was not hit
        // use the result here
    }).catch(err => {
        console.log(err);
        // an error occurred here
        if (err instanceof TimeoutError) {
            // timeout
        } else {
            // other error
        }
    })
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM