Skip to content

Instantly share code, notes, and snippets.

@chrisjhoughton
Created December 10, 2013 13:02
Show Gist options
  • Star 26 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save chrisjhoughton/7890239 to your computer and use it in GitHub Desktop.
Save chrisjhoughton/7890239 to your computer and use it in GitHub Desktop.
Wait for a global variable to exist on the page.
var waitForGlobal = function(key, callback) {
if (window[key]) {
callback();
} else {
setTimeout(function() {
waitForGlobal(key, callback);
}, 100);
}
};
waitForGlobal("jQuery", function() {
console.log("found it");
});
@waghcwb
Copy link

waghcwb commented Mar 22, 2019

Here's support for sub-keys on window, eg: window.MY.fn

function waitForGlobal({ key, sub }, callback) {
  if (window[key]) {
    if (sub) {
      if (window[key][sub]) {
        callback()
      } else {
        setTimeout(function() {
          waitForGlobal({ key, sub }, callback)
        }, 100)
      }
    } else {
      callback()
    }
  } else {
    setTimeout(function() {
      waitForGlobal({ key, sub }, callback)
    }, 100)
  }
}

@JumpLink
Copy link

JumpLink commented May 11, 2020

Here another version for nested sub keys:

  window.checkNested = function(obj, args) {
    for (var i = 0; i < args.length; i++) {
      if (!obj || !obj.hasOwnProperty(args[i])) {
        return false;
      }
      obj = obj[args[i]];
    }
    return true;
  }

  window.waitForGlobal = function(keyPath, callback) {
    var args = keyPath.split('.');
    if (window.checkNested(window, args)) {
      callback();
    } else {
      setTimeout(function() {
        window.waitForGlobal(keyPath, callback);
      }, 100);
    }
  }

Usage:

window.waitForGlobal("MY.fn", function() {
  console.debug("MY.fn is defined: ", window.MY.fn);
});

Note: The keyPath can also contain more subkeys, e.g. MY.Object.property.functionName or none child property: jQuery

@fawzanm
Copy link

fawzanm commented Mar 25, 2021

Thank you for saving my head.

@tsgrgo
Copy link

tsgrgo commented Dec 22, 2022

I wrote a more generalized function that lets you busy wait for any condition. It returns a promise instead of using a callback.

/**
 * Function to wait for predicates.
 * @param {function() : Promise.<Boolean> | function() : Boolean} predicate
 * - A function that returns or resolves a bool
 * @param {Number} [timeout] - Optional maximum waiting time in ms after rejected
 */
export function waitFor(predicate, timeout) {
    return new Promise((resolve, reject) => {
        let running = true;

        const check = async () => {
            const res = await predicate();
            if (res) return resolve(res);
            if (running) setTimeout(check, 100);
        };

        check();

        if (!timeout) return;
        setTimeout(() => {
            running = false;
            reject();
        }, timeout);
    });
}

Here is an example to check for global properties without timeout:

await waitFor(() => window.hasOwnProperty('propName'));

// Or if propName is not falsey if defined:
await waitFor(() => window.propName);

// You can also assign it to a variable
const propName = await waitFor(() => window.propName);

And if you want timeout:

try {
    await waitFor(() => window.hasOwnProperty('propName'), 2000);
} catch (err) {
    console.error('timed out')
}

@flashlab
Copy link

I wrote a more generalized function that lets you wait for any condition. It returns a promise instead of using a callback.

/**
 * Function to wait for predicates.
 * @param {function() : Boolean} predicate - A function that returns a bool
 * @param {Number} [timeout] - Optional maximum waiting time in ms after rejected
 */
export function waitFor(predicate, timeout) {
  return new Promise((resolve, reject) => {
    const check = () => {
      console.log('checking', predicate());
      if (!predicate()) return;
      clearInterval(interval);
      resolve();
    };
    const interval = setInterval(check, 100);
    check();

    if (!timeout) return;
    setTimeout(() => {
      clearInterval(interval);
      reject();
    }, timeout);
  });
}

Here is an example to check for global properties without timeout:

await waitFor(() => window.hasOwnProperty('propName'));

And if you want timeout:

try {
    await waitFor(() => window.hasOwnProperty('propName'), 2000);
} catch (err) {
    console.error('timed out')
}

If you want to check nested sub keys, something like this might work:

await waitFor(() => window?.MY?.Object?.property?.functionName);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment