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?
The following will keep looking for someVariable until it is found. It checks every 0.25 seconds.
function waitForElement(){
if(typeof someVariable !== "undefined"){
//variable exists, do what you want
}
else{
setTimeout(waitForElement, 250);
}
}
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:
/**
* 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);
I would prefer this code:
function checkVariable() {
if (variableLoaded == true) {
// Here is your next action
}
}
setTimeout(checkVariable, 1000);
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.
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
//First define some delay function which is called from async function
function __delay__(timer) {
return new Promise(resolve => {
timer = timer || 2000;
setTimeout(function () {
resolve();
}, timer);
});
};
//Then Declare Some Variable Global or In Scope
//Depends on you
let Variable = false;
//And define what ever you want with async fuction
async function some() {
while (!Variable)
await __delay__(1000);
//...code here because when Variable = true this function will
};
////////////////////////////////////////////////////////////
//In Your Case
//1.Define Global Variable For Check Statement
//2.Convert function to async like below
var isContinue = false;
setTimeout(async function () {
//STOPT THE FUNCTION UNTIL CONDITION IS CORRECT
while (!isContinue)
await __delay__(1000);
//WHEN CONDITION IS CORRECT THEN TRIGGER WILL CLICKED
$('a.play').trigger("click");
}, 1);
/////////////////////////////////////////////////////////////
Also you don't have to use setTimeout in this case just make ready function asynchronous...
You can use this:
var refreshIntervalId = null;
refreshIntervalId = setInterval(checkIfVariableIsSet, 1000);
var checkIfVariableIsSet = function()
{
if(typeof someVariable !== 'undefined'){
$('a.play').trigger("click");
clearInterval(refreshIntervalId);
}
};
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
});
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.
Shorter way:
var queue = function (args){
typeof variableToCheck !== "undefined"? doSomething(args) : setTimeout(function () {queue(args)}, 2000);
};
You can also pass arguments
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
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 an adaptation of the answer by #dnuttle that I would suggest using.
The advantage of using a try-catch block is that if any part of the code you are trying to execute fails, the whole block fails. I find this useful because it gives you a kind of transaction; everything or nothing gets done.
You should never write code that could end up in an endless loop due to external factors. This is exactly what would happen if you were waiting for a response from an ajax request and the server doesn't respond. I think it's good practice to have a timeout for any questionable loops.
let time = 0; // Used to keep track of how long the loop runs
function waitForElement() {
try {
// I'm testing for an element, but this condition can be
// any reasonable condition
if (document.getElementById('test') === null) {
throw 'error';
}
// This is where you can do something with your variable
// document.getElementById('test').addEventListener....
// or call a function that uses your value
} catch (error) {
// Loop stops executing if not successful within about 5 seconds
if (time > 5000) {
// I return false on failure so I can easily check for failure
return false;
} else {
// Increment the time and call the function again
time += 250;
setTimeout(waitForElement, 250);
}
}
}
// Call the function after the definition, ensures that time is set
waitForElement();
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")
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.
while (typeof myVar == void(0)) {
if ( typeof myVar != void(0)) {
console.log(myVar);
}
}
This makes use of the typeof operator which only returns undefined if variable is not declared yet. Should be applicable in every type of javascript.
I am trying to call a function to get a value from a 'subproduct' table and insert it in to another table. However the value which I am returning is not fetching the latest value from table and it is getting returned even before the snapshot part of the function is getting executed. I want it to run synchronously. Is there a better way in which it can be written.
function getGSTvalues(para1) {
var gstVar = 1;
var gstVarPromise = SubProductRef.once("value").then(function(snapshot) {
snapshot.forEach(function(child) {
if (para1 == child.val().subproductName) {
gstvar = child.val().gst;
console.log("InsidePromise" + gstVar);
}
});
console.log("outside fun : " + gstVar);
});
console.log("outside fun1 : " + gstVar);
return gstVar;
};
This is where I am calling the above function:
var gstans = getGSTvalues($('#edit_ProductSubType').val());
Any help would be appreciated
Using synchronous logic would be a big step backwards. The best solution here would be to use the asynchronous pattern correctly and provide a callback function to getGSTvalues() which is executed after the async operation completes and receives the result as an argument. Try this:
function getGSTvalues(para1, cb) {
var gstVar = 1;
var gstVarPromise = SubProductRef.once("value").then(function(snapshot) {
snapshot.forEach(function(child) {
if (para1 == child.val().subproductName) {
gstVar = child.val().gst;
}
});
cb && cb(gstVar);
});
};
getGSTvalues($('#edit_ProductSubType').val(), function(gst) {
console.log(gst);
// work with the value here...
});
Another alternative would be to return the promise from SubProductRef from getGSTvalues() and apply then() on that in the calling scope, although this would render the function largely redundant.
Also note that JS is case sensitive so gstVar is not the same as gstvar. I corrected this above.
my function delete data from store but at the same time i want to save the deletion time so i tried use return twice is right like i wrote in the function or it cause any problem later ? thank for help
function deleteStudent( $indexedDB, student, $scope, studentId, userId) {
return $indexedDB.openStore('student', function (store) {
student["delete_time"] = new Date().toISOString();
return saveItemInStore(store, student, userId);
return store.delete(studentId);
});
}
The only problem this will cause is that the second return statement will never execute.
Possibly you could re-write the return statement like this...
return (saveItemInStore(store, student, userId) && store.delete(studentId));
This will return "true" if both statements succeed. Additionally "store.delete" will not execute if "saveItemInStore" fails. You'll need to determine if this is appropriate for your situation.
Objects are tailor-made to allow you to return multiple pieces of information from a function. Just create as many properties as desired on a single object and return that object. Of course, the code that calls the function needs to know that that is what is being returned and use it accordingly.
var desiredInfo = myFunc();
document.write("<p>I learned both to " + desiredInfo.first + " and to " + desiredInfo.second + ".</p>");
function myFunc() {
var objToReturn = {};
var someAdvice = "buy low";
objToReturn.first = someAdvice;
var moreAdvice = "sell high";
objToReturn.second = moreAdvice;
return objToReturn;
}
Perhaps something like this fits your bill.
function mytestfunc(){
alert("I will be called first")
return (function(){
alert("I will be called second");
//saveItemInStore placeholder
return (function(){
alert("I will be called third")
//store.delete placeholder
})();
})();
}
mytestfunc();
Additionally, for reference check this stackoverflow question to know more about self executing functions.
In the below code, I want to know what would be the value of tabId inside doStuffWithReport function. Would it be the same value of tabId that was sent while calling sendMessage or it might change during the course of period?
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
// we suppose that tabId is 5.
function doStuffWithReport(report) {
// what would be the value of tabId? still 5? or it might change to
// something else if, in the meantime, we received another
// call for chrome.tabs.onUpdated?
}
// we are sending a message to tabId 5.
chrome.tabs.sendMessage(tabId, {
text: 'report_me'
}, doStuffWithReport);
});
Edit: I tested it myself. It remains the same, i.e., tabId would remain 5 even if there is another call on chrome.tab.onUpdated.
Well, first let's simplify the code to look at the underlying behavior:
function outside(){
var out = 5;
function inside(){
console.log(out);
}
inside();
}
In this example it will obviously print out 5 when outside is called, but since inside is only defined locally, it will be undefined unless called from within outside.
To make it a bit more complex, let's not make out static and have it based on a parameter:
function outside(out){
function inside(){
console.log(out);
}
inside();
}
Now it is pretty much the same as before and will print out whatever we use as a parameter right away. Let's make it a bit more async by having inside be called after a random amount of time of up to a second and compare the then current value of out with the value of out that is printed at the time inside is called while calling it several times consecutively.
function outside(out){
function inside(){
var dt = Date.now();
console.log(dt + ' : ' +out);
}
var n = Math.floor(Math.random() * 1000);
var d = Date.now()+n;
console.log(d + ' : ' + out);
setTimeout(inside,n);
}
for(var x=0;x<25;x++){outside(x);}
From the output of this, we can see that the value of out that inside has at the time of being called is the same value as when we set the timeout for inside to be called.
From this we can say that tabId would indeed still be 5 when doStuffWithReport is called.
I have an problem and I guess the solution is using callbacks. But I'm not sure how.
When starting node.js the following code gets called:
// create a new player and insert in the database
// the player gets inserted in the database correctly
var player1 = new player();
console.log(player1.id); // undefined
My constructor looks like this:
function Player(id) {
// if we don't have a id, this player needs to be created
this.id = (typeof id !== 'number') ? this.createPlayer() : this.setId(id);
}
Then I create a player in the database:
Player.prototype.createPlayer = function () {
var playerId = 0;
connection.query("INSERT INTO players SET `created_at` = now()", function (err, result) {
if (result) {
playerId = result.insertId;
console.log("Successfully inserted player no. " + playerId);
this.id = parseInt(playerId, 10);
return this.id;
} else {
console.log("Something went wrong: " + err);
}
});
};
My guess is I need some form of callback, but I'm not sure how I will do this. A small push in the right direction would be great!
This is the use case of node.js EventEmitter. You can use events to let the application know that your object initialization is completed and it is ready to be used. (I haven't tried the code, but its should work this way, let me know if it doesn't)
var EventEmitter = require('events').EventEmitter;
var util = require('util');
// Define your class like
function Player(id) {
// if we don't have a id, this player needs to be created
this.id = (typeof id !== 'number') ? this.createPlayer() : this.setId(id);
}
util.inherits(Player, EventEmitter);
Player.prototype.createPlayer = function (cb) {
connection.query(sql, function (err, result) {
if (result) {
// to avoid triggering event before binding.
process.nextTick(function () {
// success! passing null as first argument and data as second
this.emit('load', null, this.id);
});
} else {
process.nextTick(function () {
this.emit('load', err, null); // passing err as first argument
});
}
});
};
// And, use your class like
var player1 = new player();
player1.on('load', function (err, id) {
console.log(player1.id);
});
As per you comment, createPlayer is not always called, i.e. only on certain condition. so you could use the same emit in case where you don't want to call createPlayer.
Hope that helps
In Node.js there are a number of ways to queue up a callback function. They are all documented here: http://nodejs.org/api/timers.html#timers_setimmediate_callback_arg
One example for adding two numbers and passing the result to a callback would be:
function addWithCallback(a, b, callback) {
process.setImmediate(callback, a+b);
}
Just like that you could do:
addWithCallback(1,3,foo);
and foo would be queued into the event loop and passed the result of 1+3 at execution time. Also check out:
http://howtonode.org/understanding-process-next-tick and setImmediate vs. nextTick
Definitely a complete solution to your question, but hopefully the "small push in the right direction" you wanted :)
Basically a callback is just a function to call then something is done
ie
function asyncAdd(v1,v2,callback){
var total = v1 + v2;
callback(total);
}
asyncAdd(1,2,function(t){
alert(t);
});
Contrast this with:
syncAdd(v1,v2){
return total;
}
Hopefully this should give you enough to get started.
Much better explanation here: http://recurial.com/programming/understanding-callback-functions-in-javascript/