[jquery] While variable is not defined - wait

I have a click event that is triggered from another place automatically for the first time. My problem is that it runs too soon, since the required variables are still being defined by Flash and web services. So right now I have:

(function ($) {
    $(window).load(function(){
        setTimeout(function(){
            $('a.play').trigger("click");
        }, 5000);
    });
})(jQuery);

The problem is that 5 seconds for a person with a slow internet connection could be too fast and vice versa, for a person with a fast internet connection, it's too slow.

So how should I do the delay or timeout until someVariable is defined?

This question is related to jquery variables timeout delay

The answer is


You can use this:

var refreshIntervalId = null;
refreshIntervalId = setInterval(checkIfVariableIsSet, 1000);

var checkIfVariableIsSet = function()
{
    if(typeof someVariable !== 'undefined'){
        $('a.play').trigger("click");
        clearInterval(refreshIntervalId);
    }
};

Very late to the party but I want to supply a more modern solution to any future developers looking at this question. It's based off of Toprak's answer but simplified to make it clearer as to what is happening.

<div>Result: <span id="result"></span></div>

<script>
    var output = null;
    
    // Define an asynchronous function which will not block where it is called.
    async function test(){
        // Create a promise with the await operator which instructs the async function to wait for the promise to complete.
        await new Promise(function(resolve, reject){
            // Execute the code that needs to be completed.
            // In this case it is a timeout that takes 2 seconds before returning a result. 
            setTimeout(function(){
                // Just call resolve() with the result wherever the code completes.
                resolve("success output");
            }, 2000);
            
            // Just for reference, an 'error' has been included.
            // It has a chance to occur before resolve() is called in this case, but normally it would only be used when your code fails.
            setTimeout(function(){
                // Use reject() if your code isn't successful.
                reject("error output");
            }, Math.random() * 4000);
        })
        .then(function(result){ 
            // The result variable comes from the first argument of resolve().
            output = result; 
        })
        .catch(function(error){ 
            // The error variable comes from the first argument of reject().
            // Catch will also catch any unexpected errors that occur during execution.
            // In this case, the output variable will be set to either of those results.
            if (error) output = error; 
        });
        
        // Set the content of the result span to output after the promise returns.
        document.querySelector("#result").innerHTML = output;
    }
    
    // Execute the test async function.
    test();

    // Executes immediately after test is called.
    document.querySelector("#result").innerHTML = "nothing yet";
</script>

Here's the code without comments for easy visual understanding.

var output = null;

async function test(){
    await new Promise(function(resolve, reject){
        setTimeout(function(){
            resolve("success output");
        }, 2000);

        setTimeout(function(){
            reject("error output");
        }, Math.random() * 4000);
    })
    .then(function(result){ 
        output = result; 
    })
    .catch(function(error){ 
        if (error) output = error; 
    });

    document.querySelector("#result").innerHTML = output;
}

test();

document.querySelector("#result").innerHTML = "nothing yet";

On a final note, according to MDN, Promises are supported on all modern browsers with Internet Explorer being the only exception. This compatibility information is also supported by caniuse. However with Bootstrap 5 dropping support for Internet Explorer, and the new Edge based on webkit, it is unlikely to be an issue for most developers.


Object.defineProperty(window, 'propertyName', {
    set: value => {
        this._value = value;
        // someAction();
    },
    get: () => this._value
});

or even if you just want this property to be passed as an argument to a function and don't need it to be defined on a global object:

Object.defineProperty(window, 'propertyName', { set: value => someAction(value) })

However, since in your example you seem to want to perform an action upon creation of a node, I would suggest you take a look at MutationObservers.


I have upvoted @dnuttle's answer, but ended up using the following strategy:

// On doc ready for modern browsers
document.addEventListener('DOMContentLoaded', (e) => {
  // Scope all logic related to what you want to achieve by using a function
  const waitForMyFunction = () => {
    // Use a timeout id to identify your process and purge it when it's no longer needed
    let timeoutID;
    // Check if your function is defined, in this case by checking its type
    if (typeof myFunction === 'function') {
      // We no longer need to wait, purge the timeout id
      window.clearTimeout(timeoutID);
      // 'myFunction' is defined, invoke it with parameters, if any
      myFunction('param1', 'param2');
    } else {
      // 'myFunction' is undefined, try again in 0.25 secs
      timeoutID = window.setTimeout(waitForMyFunction, 250);
    }
  };
  // Initialize
  waitForMyFunction();
});

It is tested and working! ;)

Gist: https://gist.github.com/dreamyguy/f319f0b2bffb1f812cf8b7cae4abb47c


I prefer something simple like this:

function waitFor(variable, callback) {
  var interval = setInterval(function() {
    if (window[variable]) {
      clearInterval(interval);
      callback();
    }
  }, 200);
}

And then to use it with your example variable of someVariable:

waitFor('someVariable', function() {
  // do something here now that someVariable is defined
});

Note that there are various tweaks you can do. In the above setInterval call, I've passed 200 as how often the interval function should run. There is also an inherent delay of that amount of time (~200ms) before the variable is checked for -- in some cases, it's nice to check for it right away so there is no delay.


Instead of using the windows load event use the ready event on the document.

$(document).ready(function(){[...]});

This should fire when everything in the DOM is ready to go, including media content fully loaded.


Here's an example where all the logic for waiting until the variable is set gets deferred to a function which then invokes a callback that does everything else the program needs to do - if you need to load variables before doing anything else, this feels like a neat-ish way to do it, so you're separating the variable loading from everything else, while still ensuring 'everything else' is essentially a callback.

var loadUser = function(everythingElse){
    var interval = setInterval(function(){
      if(typeof CurrentUser.name !== 'undefined'){
        $scope.username = CurrentUser.name;
        clearInterval(interval);
        everythingElse();
      }
    },1);
  };

  loadUser(function(){

    //everything else

  });

You could have Flash call the function when it's done. I'm not sure what you mean by web services. I assume you have JavaScript code calling web services via Ajax, in which case you would know when they terminate. In the worst case, you could do a looping setTimeout that would check every 100 ms or so.

And the check for whether or not a variable is defined can be just if (myVariable) or safer: if(typeof myVariable == "undefined")


With Ecma Script 2017 You can use async-await and while together to do that And while will not crash or lock the program even variable never be true

_x000D_
_x000D_
//First define some delay function which is called from async function_x000D_
function __delay__(timer) {_x000D_
    return new Promise(resolve => {_x000D_
        timer = timer || 2000;_x000D_
        setTimeout(function () {_x000D_
            resolve();_x000D_
        }, timer);_x000D_
    });_x000D_
};_x000D_
_x000D_
//Then Declare Some Variable Global or In Scope_x000D_
//Depends on you_x000D_
let Variable = false;_x000D_
_x000D_
//And define what ever you want with async fuction_x000D_
async function some() {_x000D_
    while (!Variable)_x000D_
        await __delay__(1000);_x000D_
_x000D_
    //...code here because when Variable = true this function will_x000D_
};_x000D_
////////////////////////////////////////////////////////////_x000D_
//In Your Case_x000D_
//1.Define Global Variable For Check Statement_x000D_
//2.Convert function to async like below_x000D_
_x000D_
var isContinue = false;_x000D_
setTimeout(async function () {_x000D_
    //STOPT THE FUNCTION UNTIL CONDITION IS CORRECT_x000D_
    while (!isContinue)_x000D_
        await __delay__(1000);_x000D_
_x000D_
    //WHEN CONDITION IS CORRECT THEN TRIGGER WILL CLICKED_x000D_
    $('a.play').trigger("click");_x000D_
}, 1);_x000D_
/////////////////////////////////////////////////////////////
_x000D_
_x000D_
_x000D_

Also you don't have to use setTimeout in this case just make ready function asynchronous...


async, await implementation, improvement over @Toprak's answer

(async() => {
    console.log("waiting for variable");
    while(!window.hasOwnProperty("myVar")) // define the condition as you like
        await new Promise(resolve => setTimeout(resolve, 1000));
    console.log("variable is defined");
})();
console.log("above code doesn't block main function stack");

After revisiting the OP's question. There is actually a better way to implement what was intended: "variable set callback". Although the below code only works if the desired variable is encapsulated by an object (or window) instead of declared by let or var (I left the first answer because I was just doing improvement over existing answers without actually reading the original question):

let obj = encapsulatedObject || window;
Object.defineProperty(obj, "myVar", {
    configurable: true,
    set(v){
        Object.defineProperty(obj, "myVar", {
            configurable: true, enumerable: true, writable: true, value: v });
        console.log("window.myVar is defined");
    }
});
    

see Object.defineProperty or use es6 proxy (which is probably overkill)


If you are looking for more:

_x000D_
_x000D_
/**
 * combining the two as suggested by @Emmanuel Mahuni,
 * and showing an alternative to handle defineProperty setter and getter
 */


let obj = {} || window;
(async() => {
  let _foo = await new Promise(res => {
    Object.defineProperty(obj, "foo", { set: res });
  });
  console.log("obj.foo is defined with value:", _foo);
})();
/*
IMPORTANT: note that obj.foo is still undefined
the reason is out of scope of this question/answer
take a research of Object.defineProperty to see more
*/

// TEST CODE

console.log("test start");
setTimeout(async () => {
  console.log("about to assign obj.foo");
  obj.foo = "Hello World!";
  // try uncomment the following line and compare the output
  // await new Promise(res => setTimeout(res));
  console.log("finished assigning obj.foo");
  console.log("value of obj.foo:", obj.foo); // undefined
  // console: obj.foo is defined with value: Hello World!
}, 2000);
_x000D_
_x000D_
_x000D_


I would prefer this code:

function checkVariable() {

   if (variableLoaded == true) {
       // Here is your next action
   }
 }

 setTimeout(checkVariable, 1000);

Shorter way:

   var queue = function (args){
      typeof variableToCheck !== "undefined"? doSomething(args) : setTimeout(function () {queue(args)}, 2000);
};

You can also pass arguments


Examples related to jquery

How to make a variable accessible outside a function? Jquery assiging class to th in a table Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Getting all files in directory with ajax Bootstrap 4 multiselect dropdown Cross-Origin Read Blocking (CORB) bootstrap 4 file input doesn't show the file name Jquery AJAX: No 'Access-Control-Allow-Origin' header is present on the requested resource how to remove json object key and value.?

Examples related to variables

When to create variables (memory management) How to print a Groovy variable in Jenkins? What does ${} (dollar sign and curly braces) mean in a string in Javascript? How to access global variables How to initialize a variable of date type in java? How to define a variable in a Dockerfile? Why does foo = filter(...) return a <filter object>, not a list? How can I pass variable to ansible playbook in the command line? How do I use this JavaScript variable in HTML? Static vs class functions/variables in Swift classes?

Examples related to timeout

Waiting for Target Device to Come Online Spring Boot Java Config Set Session Timeout How to dispatch a Redux action with a timeout? Spring Boot REST API - request timeout? 5.7.57 SMTP - Client was not authenticated to send anonymous mail during MAIL FROM error How to set timeout in Retrofit library? How to set connection timeout with OkHttp How to modify the nodejs request default timeout time? How to handle ETIMEDOUT error? Timeout for python requests.get entire response

Examples related to delay

Delaying function in swift How to create a delay in Swift? How to make java delay for a few seconds? Proper way to wait for one function to finish before continuing? Javascript sleep/delay/wait function How can I perform a short delay in C# without using sleep? How to create javascript delay function JavaScript sleep/wait before continuing Adding delay between execution of two following lines How to put a delay on AngularJS instant search?