Reputation: 513
I have a Typescript function called delay() that is invoked in async/await mode.
play(){
(async () => {
await this.delay(90000);
this.player.play();
})();
}
delay(ms: number) {
return new Promise(resolve => setTimeout(resolve, ms));
}
Is there a way to "kill/interrupt" the setTimeout before complete the 90 seconds and start the counting again when the "play" function is invoked again?
Upvotes: 0
Views: 2542
Reputation: 36219
You probably want something like
const delay = (ms: number) => {
let id;
const promise = new Promise(resolve => {
id = setTimeout(resolve, ms);
});
return {
id, promise
};
}
const play = () => {
const { id, promise } = delay(1000);
promise.then(() => console.log("Promise called"));
// Or call this to cancel
clearTimeout(id);
};
But I'd implement this in another way:
const Timer = (ms: number) => {
let id: number;
const start = () => new Promise(resolve => {
if (id === -1) {
throw new Error('Timer already aborted');
}
id = setTimeout(resolve, ms);
});
const abort = () => {
if (id !== -1 || id === undefined) {
clearTimeout(id);
id = -1;
}
}
return {
start, abort
}
};
const timer = Timer(1000);
timer.start().then(() => console.log("done after 1000ms"));
timer.abort(); // this would abort the operation
// Calling timer.abort() before timer.start() would throw an error as well.
Upvotes: 9
Reputation: 912
You can read here about Promise cancelation.
I have created a class that can be useful to solve your problem
My class is using the advantages of bluebird library
class Delayer {
constructor() {
this.Promise = require('bluebird');
this.Promise.config({
cancellation: true
})
this.promise = null;
}
delay(ms) {
if(this.promise) {
this.promise.cancel();
}
this.promise = new this.Promise(resolve => setTimeout(resolve, ms));
return this.promise;
}
}
Your code usage
// you need to run `npm install bluebird --save`
const delayer = new Delayer(); // create a new instance of delayer to work with
play(){
(async () => {
await delayer.delay(90000);
this.player.play();
})();
}
Upvotes: 1
Reputation: 1
Take a look at "debounced" function.
import { debounce } from “lodash”;
class Player {
constructor() {
this.delayedPlay = debounce(this.play.bind(this), 9000);
}
play() {
/* do stuff here */
}
}
If you make a second call of debouncePlay
in less than 90 seconds before the first call, the first call will be canceled and a new timer will start.
Here is a more detailed explanation of the debounce function.
Upvotes: 0
Reputation: 966
check if this can help. idea is we create a settimeout reference variable using which we can do clearTimeout, to stop previous settimeout execution.
play = (()=>{let timeoutRef; return((number)=>{if(timeoutRef){clearTimeout(timeoutRef)};timeoutRef = setTimeout(()=>console.log("hello",number),number)})})()
mind the code formatting, I used jsconsole to type in my code.:)
Upvotes: 0
Reputation: 946
Since your cancel function returns a promise, and ES6 does not allow you to cancel a promise. Promise returns either success or failed value.
To achieve cancelation of promise either use
RxJS observables or third-party libraries like the bluebird
Upvotes: 0
Reputation: 48582
setTimeout
returns a value. Save the value somewhere, then when you want to "kill/interrupt" it, call clearTimeout
on it.
Upvotes: 0