Home > database >  Two JavaScript funtions "await" for something that will resolve, is there any way to avoid
Two JavaScript funtions "await" for something that will resolve, is there any way to avoid

Time:07-08

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

CodePudding user response:

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
}

CodePudding user response:

There is no way navigating around a promise/async...await based approach but ...

... from my above comment ...

"How about returning instance from the async load function. One also might consider turning it into a function which encapsulates instance."

const load = (function () {
  let instance;

  return (async function load () {
    if ('undefined' === typeof instance) {

      instance = await (new Promise(resolve =>
        setTimeout(resolve, 3000, [])
      ));
    }
    return instance;
  });
}());

async function foo() {
  const instance = await load();

  console.log('foo ... instance ...', instance)
}
async function bar() {
  const instance = await load();

  console.log('bar ... instance ...', instance)
}

foo(); // 2nd
bar(); // 3rd

setTimeout(bar, 6000); // 5th
setTimeout(bar, 6000); // 6th

setTimeout(() =>
  console.log('(typeof instance) ?..', (typeof instance)), 5000 // 4th
);
console.log('(typeof instance) ?..', (typeof instance)); // 1st
.as-console-wrapper { min-height: 100%!important; top: 0; }

  • Related