简体   繁体   中英

stop await setTimeOut function

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?

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.

setTimeout returns a value. Save the value somewhere, then when you want to "kill/interrupt" it, call clearTimeout on it.

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

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.:)

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.

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();
    })();
 }

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