Search code examples
javascriptnode.jsasync-awaitpromisecancellation

What is the best way to handle function interrupts in javascript


Basically I have two async functions. One of them is a simple 5 second timeout and the other is a complicated async function with multiple steps. Here is an example

const delay = ms => new Promise(res => setTimeout(res, ms));

class Runner {
  
  async start() {

      let printStuff = async () => {
        for(let i = 0 ; i < 50; i++){
          console.log(i);
          await delay(50);
        }
      }


      let printLetters = new Promise(async function(resolve, reject) {
        
        const length = Math.floor(Math.random() * 10)
        
        //dont know how long this will take
        for(let i = 0; i < length; i++){
          await printStuff();
        }
        
        resolve('letters');
      });

      let timeout = new Promise(async function(resolve, reject) {
        await delay(5000);
        resolve('timeout')
      });
      
      const finished = await Promise.all([timeout, printLetters]);
      if(finished === 'timeout'){
        this.stop();
      }
  }
  
  stop(){
    //stop printing stuff instantly
  }

}

const myRunner = new Runner();

myRunner.start();
//could call myRunner.stop(); if the user canceled it

The way I would implement this would add a global variable and include an if statement inside the for loop to check if the interrupt has been called but I am wondering if there is a better way to implement this. An issue with this solution would be it would print a few more numbers. I would have to add another check to the other for loop and this could get messy quickly.


Solution

  • Here is a simple demo that uses my own library.

    import { CPromise } from "c-promise2";
    
    const task = CPromise.promisify(function* () {
      let printStuff = CPromise.promisify(function* () {
        for (let i = 0; i < 10; i++) {
          console.log(i);
          yield CPromise.delay(100);
        }
      });
    
      const length = Math.floor(Math.random() * 10) + 3;
    
      //dont know how long this will take
      for (let i = 0; i < length; i++) {
        yield printStuff();
      }
    
      return "letters";
    });
    
    const promise = task()
      .timeout(5000)
      .then(
        (result) => console.log(`Done: ${result}`),
        (err) => console.warn(`Fail: ${err}`)
      );
    
    setTimeout(() => {
      promise.cancel();
    }, 2000);