Skip to content
Advertisement

Two JavaScript funtions “await” for something that will resolve, is there any way to avoid it?

I’ve to admin I need to read more about this topic. Anyways, here is the background:

  1. foo and bar need to use instance, which is a result of a async call
  2. load is checking if instance is undefined, to avoid re-loading it

Example:

let instance;

// Will resolve in 5 seeconds when instance is undefined
async load() {
  if ('undefined' !== typeof instance) {
    return;
  }

  instance = await new Promise(resolve => setTimeout(() => {
    resolve([]);
  }, 5000));
}

async foo() {
  await load();

  // Use instance
}

async bar() {
  await load();

  // Use instance
}

Timeline:

  • foo() will be called after 1 seconds (say t1)
  • bar() will be called after 3 seconds (say t3)

Conclusions:

  • load() will resolve at t6 (t1 + t5) for the first time
  • load() will resolve at t8 (t3 + t5) for the second time
  • Any call to load() after t6 will return immediately (that’s what I want in the first place)
  • There is no way to avoid the second load()

So to the question: is there any way to avoid the second load() (and the second resolve of the promise)? Note that foo and bar will be invoked by a framework, so I cannot “control” their invocation.

EDIT: https://www.jonmellman.com/posts/singleton-promises this is the concept of “singleton promises” relative to @Amir question

EDIT: looking at the answer (good ones!) this is quite real code of what I’m trying to do. This works as per answer, but it’s inconvenient (need to const instance = await this.load()):

export default class {
  module;

  async load() {
    if (!this.module) {
      this.module = import('amodule').then(({ default: Ctor }) => {    
        return new Ctor();
      });
    }

    return this.module;
  }

  async foo() {
    const instance = await this.load();
  }

  async bar({ params }) {
    const instance = await this.load();
  }
}

Advertisement

Answer

I hope I understood you correctly. You can hold the raw promise and always return it. Once it’s in resolve state it, awaiting it will return the value without re-running anything.

let promise;

load() {
  if(!promise){
    promise = new Promise(resolve => setTimeout(() => {
      resolve([]);
    }, 5000));
  }

  return promise; // await it outside
}
User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement