Search code examples
javascriptpromiseasync-awaitsettimeout

Create a Promise that resolves when variable is not undefined


I'm trying to Create a Promise that resolves when variable is not undefined.

Code example

https://codesandbox.io/s/quizzical-feynman-ktvox?file=/src/index.js

let fetchedPromise = new Promise((resolve, reject) => {
  const check = ()=>{
    setTimeout(() =>{
    console.log("checking")
    if (dataFetched) resolve(dataFetched);
    else check()
    }, 100);
  }
  check()
});

const waitForDataFromAnotherComponent = async () => {
  let result = await fetchedPromise;
  console.log("Result: ", result);
};

const assignData = () => {
  setTimeout(() => {
    dataFetched = 1000;
    console.log(dataFetched);
  }, 5000)
};

waitForDataFromAnotherComponent();
assignData();

This works but I find it inefficient as it's callstack prone and seems wrong.

Other non-working solutions I've tried:

//-------------SOLUTION 1
let fetchedPromise = new Promise((resolve, reject) => {
  const check = ()=>{
    if (dataFetched) resolve(dataFetched);
    else check()
  }
  check()
});

//--------------------SOLUTION 2
let fetchedPromise = new Promise((resolve, reject) => {
   if (dataFetched) resolve(dataFetched);
});

Scenario

I need a function like solution 3 that doesn't rely on setTimeout


Solution

  • Solved by using Javascript Proxy

    Basically I assign a Proxy Object to dataFetched that listens to changes. I re-create the function of listening due to the fact that it must include resolve()

    let dataFetched
    let x = {
      aListener: function (val) {},
      set a(val) {
        dataFetched = val;
        this.aListener(val);
      },
      get a() {
        return dataFetched;
      },
      registerListener: function (listener) {
        this.aListener = listener;
      }
    };
    
    let fetchedPromise = new Promise((resolve, reject) => {
      x.registerListener(function (val) {
        console.log("yeyyyyyyyyyyyyyyy");
        if (dataFetched) resolve(dataFetched);
      });
    });
    
    const waitForDataFromAnotherComponent = async () => {
      let result = await fetchedPromise;
      console.log("Result: ", result);
    };
    const assignData = async () => {
      await new Promise((resolve, reject) =>
        setTimeout(() => {
          x.a = 1000;
          console.log(dataFetched);
          resolve(dataFetched);
        }, 1000)
      );
    };
    
    waitForDataFromAnotherComponent();
    assignData();
    

    EDIT

    Actually it's possible to externalize the resolve() function of the promise but with some downsides as stated here

    example

    let dataFetched
    var promiseResolve, promiseReject;
    
    let x = {
      aListener: function (val) {
        if (dataFetched) promiseResolve(dataFetched);
    },
      set a(val) {
        dataFetched = val;
        this.aListener(val);
      },
      get a() {
        return dataFetched;
      },
      registerListener: function (listener) {
        this.aListener = listener;
      }
    };
    
    let fetchedPromise = new Promise((resolve, reject) => {
     promiseResolve = resolve;
      promiseReject = reject;
    });