1

I have a class with multiple methods, each method either call async functions, or manipulating data created by other methods.

How can I make sure that calling class methods would wait for previous method finish before proceeding?

Here is a simple example that calls random methods of the class, each method takes random number of seconds to execute, I need to make sure that each called method waited for result of previous method:

class Test
{
  constructor()
  {
    //ignore the constructor, it's simplified for this example and does not play any role in the question
    const list = [...Array(~~(Math.random()*3)+3)].map(e=>~~(Math.random()*3+1));
    console.log("expected: " + list);
    list.forEach(f => this["method_" + f]());
  }
  method_1()
  {
    return new Promise(resolve => setTimeout(() => 
    {
      console.log(1);
      resolve("res 1");
    }, Math.random() * 1000 + 100));
  }
  method_2()
  {
    return new Promise(resolve => setTimeout(() => 
    {
      console.log(2);
      resolve("res 2");
    }, Math.random() * 1000 + 100));
  }
  method_3()
  {
    func3();
  }
}

new Test();

function func3()
{
  new Promise(resolve => setTimeout(() => 
  {
    console.log(3);
    resolve("res 3");
  }, Math.random() * 1000 + 100));
}

I can't use then method, because each method doesn't know which method was executed before it...or can I?

I was thinking about adding a sort of queue, where called method would be placed when called, and executed when previous promise was resolved...not sure if that would be a best approach.

11
  • 1
    yes, you can use .then ... like this let p = Promise.resolve(); list.forEach(f => p = p.then(() => this["method_" + f]())); - but you get "neater" code using reduce - list.reduce((p, f) => p.then(() => this["method_" + f]()), Promise.resolve()); Commented Aug 25, 2022 at 1:32
  • 2
    You really really should just use for (const f of list) { await this["method_" + f](); } instead of forEach. Yes, you could implement such a queue as part of your instance state, but it'll become unwieldy since all your class methods become asynchronous with that. Commented Aug 25, 2022 at 1:36
  • but you can't use await directly in the constructor :p Commented Aug 25, 2022 at 1:42
  • 2
    "not all methods are returning a promise, they might only execute an async function" - don't do that. An method doing something asynchronous should always return a promise. Commented Aug 25, 2022 at 1:46
  • 2
    @vanowm Well that does return that chained promise! Commented Aug 25, 2022 at 1:50

1 Answer 1

0

Since essentially I needed make this class synchronous, using queue suggested by @Bergi works well:

class Test
{
  constructor()
  {
    this.queueList = Promise.resolve();

    //ignore the rest of the constructor, it's simplified for this example and does not play any role in the question
    const list = [...Array(~~(Math.random()*3)+3)].map(e=>~~(Math.random()*3+1));
    console.log("expected: " + list);
    list.forEach(f => this["method_" + f]());
  }
  queue(func)
  {
    return (this.queueList = this.queueList.then(func).catch(console.error));
  }
  method_1()
  {
    return this.queue(() => new Promise(resolve => setTimeout(() => 
    {
      console.log(1);
      resolve("res 1");
    }, Math.random() * 1000 + 100)));
  }
  method_2()
  {
    return this.queue(() => new Promise(resolve => setTimeout(() => 
    {
      console.log(2);
      resolve("res 2");
    }, Math.random() * 1000 + 100)));
  }
  method_3()
  {
    return this.queue(func3);
  }
}

new Test();

function func3()
{
    return new Promise(resolve => setTimeout(() => 
    {
      console.log(3);
      resolve("res 3");
    }, Math.random() * 1000 + 100));
}

Sign up to request clarification or add additional context in comments.

1 Comment

Yes, but don't forget the error handling!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.