using timedelay function in javascript - javascript

I am trying to set my localStorage key values after a certain condition becomes true but wait for 2 seconds before it can update the localStorage key value
This is what I am trying to do but it throws an exception and when it tries to set the localStorage value
if(tempArray.length <= 0){
setTimeout(function(){
this.storage.set(achkey,1);
},2000);
}
The exception says variable achkey undefined though I can use it outside the setTimeout function. How do I go about implementing the delay and setting values inside correctly? I am using ImpactJS engine which uses javascript. I am also using a plugin for my localStorage.

You need to cache this. Once you enter the setTimeout's anonymous function, this now refers to the scope of the function that you just declared.
if(tempArray.length <= 0){
var self = this; // Cache the current scope's `this`
setTimeout(function(){
self.storage.set(achkey,1);
},2000);
}

Related

Why does console log show variable that is already defined

Curios why this happens
if(typeof TEST === "undefined") {
var TEST = true;
console.log(TEST);
}
if i place in console , it returns true
if i add again in console , then no console log is shown , which is exactly how I would assume it should work.
When i place in interval , why does it continue to log the variable even though its defined ?
setInterval(function(){
if(typeof TEST === "undefined") {
var TEST = true;
console.log(TEST);
}
}, 1000);
How can you make it stop showing the log after its defined ? Without clearing the interval
If you put it in the console then var creates a variable in the top level scope. It is undefined, so you assign true to it. If you put it in the console again then it is true from the previous time.
If you put it inside a function, then it is scoped to the function, so every time you run the function you create a new scope and a new var TEST.
Declare the variable in a scope outside the function instead.
In the first case, you're testing the global variable. Once it's defined, it stays defined.
In the second case, the variable is local to the callback function. Every time the function is called, it's a new variable that isn't defined yet.
If you remove the var declaration in the setInterval() version it will assign to the global variable, and it will stay defined.
The simplest solution is probably to use let or const instead of var. If of course you have the possibility.

setTimeout in javaScript not Working correctly

I know there is an Answer for this But!! All The Answers covered with only one setTimeout in the loop this Question Looks relevant to me How do I add a delay in a JavaScript loop?
But in my Scenario I Have two setTimeout in the Script, How can this be implemented correctly with timing !! The Program works correctly but the timing what I want is not correct !!!
function clickDate(i)
{
setTimeout((function(){
alert("4");
})(),2000);
}
function clickButton(i)
{
setTimeout((function(){
alert("5");
})(),4000);
}
function doEverything(i)
{
clickDate(i);
clickButton(i);
}
for(var i = 0; i < 4; i++)
{
doEverything(i);
}
You're immediately calling the function when you pass it to setTImeout. Remove the extra parenthesis.
function clickDate(i)
{
setTimeout(function(){
alert("4");
},2000);
}
function clickButton(i)
{
setTimeout(function(){
alert("5");
},4000);
}
function doEverything(i)
{
clickDate(i);
clickButton(i);
}
for(var i = 0; i < 4; i++)
{
doEverything(i);
}
EDIT
It's a little unclear what exactly it is you want your code to do seeing as you're passing i into your function I assume you want to use it somehow. Currently you're creating timeouts that will all launch at once. You'll need to stagger the delay times if you want them to launch in sequence. The code below logs a "4" every 2 seconds and a "5" every "4" seconds by multiplying the delay time by i+1.
// Currently this code displays a 4 every 2 seconds and a 5 every 4 seconds
function clickDate(i)
{
setTimeout(function(){
console.log("4");
},2000 * (i+1));
}
function clickButton(i)
{
setTimeout(function(){
console.log("5");
},4000 * (i+1));
}
function doEverything(i)
{
clickDate(i);
clickButton(i);
}
for(var i = 0; i < 4; i++)
{
doEverything(i);
}
Hello I think you havent read documentation about javascript.
It's asynchronous and it will not wait for the event and continue the process. I will give the answer but I highly recommend to read about Javascript it's good for you only here you will get timing problem because your both the function will be called at the same time. Let me give you the example.
function clickDate(i,callback)
{
setTimeout(function(){
alert("4");
callback();//this will call anonymous function in doEverything
},2000);
}
function clickButton(i)
{
setTimeout(function(){
alert("5");
},4000);
}
function doEverything(i)
{
console.log("In loop index is " , i);
clickDate(i,function(){
clickButton(i);
});
//look closely here I have passed the function in changeData and will call that funtion from clickDate
console.log("In loop terminating index is " , i);
}
for(var i = 0; i < 4; i++)
{
doEverything(i);
}
So here console log will make you clear about asynchronous
functionality. You will see that for loop terminates as it continues
it's work and easily completed in 2 seconds so before your first alert
for loop will complete it's iteration.
Hopefully this will help.
you are calling the callback immediately by adding () to the end of function .
you need to pass the callback with timeout and it will be call for you
setTimeout(function(){
alert('hello');
} , 3000);
function functionName() {
setTimeout(function(){ //Your Code }, 3000);
}
Try this one.
Your approach to mocking asynchronous behavior in JavaScript with setTimeout is a relatively common practice. However, providing each function with its own invocation of setTimeout is an anti-pattern that is working against you simply due to the asynchronous nature of JavaScript itself. setTimeout may seem like it's forcing JS to behave in a synchronous way, thus producing the 4 4 4 4 then 5 5 you are seeing on alert with iteration of the for loop. In reality, JS is still behaving asynchronously, but because you've invoked multiple setTimeout instances with callbacks that are defined as anonymous functions and scoped within their own respective function as an enclosure; you are encapsulating control of JS async behavior away from yourself which is forcing the setTimeout's to run in a strictly synchronous manner.
As an alternative approach to dealing with callback's when using setTimeout, first create a method that provides the timing delay you want to occur. Example:
// timer gives us an empty named "placeholder" we can use later
// to reference the setTimeout instance. This is important because
// remember, JS is async. As such, setTimeout can still have methods
// conditionally set to work against it.
let timer
// "delayHandler", defined below, is a function expression which when
// invoked, sets the setTimeout function to the empty "timer" variable
// we defined previously. Setting the callback function as the function
// expression used to encapsulate setTimeout provides extendable control
// for us later on however we may need it. The "n" argument isn't necessary,
// but does provide a nice way in which to set the delay time programmatically
// rather than hard-coding the delay in ms directly in the setTimeout function
// itself.
const delayHandler = n => timer = setTimeout(delayHandler, n)
Then, define the methods intended as handlers for events. As a side-note, to help keep your JS code from getting messy quickly, wrap your event handler methods within one primary parent function. One (old school) way to do this would be to utilize the JS Revealing Module Pattern. Example:
const ParentFunc = step => {
// "Private" function expression for click button event handler.
// Takes only one argument, "step", a.k.a the index
// value provided later in our for loop. Since we want "clickButton"
// to act as the callback to "clickDate", we add the "delayHandler"
// method we created previously in this function expression.
// Doing so ensures that during the for loop, "clickDate" is invoked
// when after, internally, the "clickButton" method is fired as a
// callback. This process of "Bubbling" up from our callback to the parent
// function ensures the desired timing invocation of our "delayHandler"
// method. It's important to note that even though we are getting lost
// in a bit of "callback hell" here, because we globally referenced
// "delayHandler" to the empty "timer" variable we still have control
// over its conditional async behavior.
const clickButton = step => {
console.log(step)
delayHandler(8000)
}
// "Private" function expression for click date event handler
// that takes two arguments. The first is "step", a.k.a the index
// value provided later in our for loop. The second is "cb", a.k.a
// a reference to the function expression we defined above as the
// button click event handler method.
const clickDate = (step, cb) => {
console.log(step)
cb(delayHandler(8000))
}
// Return our "Private" methods as the default public return value
// of "ParentFunc"
return clickDate(step, clickButton(step))
}
Finally, create the for loop. Within the loop, invoke "ParentFunc". This starts the setTimeout instance and will run each time the loop is run. Example:
for(let i = 0; i < 4; i++) {
// Within the for loop, wrap "ParentFunc" in the conditional logic desired
// to stop the setTimeOut function from running further. i.e. if "i" is
// greater than or equal to 2. The time in ms the setTimeOut was set to run
// for will no longer hold true so long as the conditional we want defined
// ever returns true. To stop the setTimeOut method correctly, use the
// "clearTimeout" method; passing in "timer", a.k.a our variable reference
// to the setTimeOut instance, as the single argument needed to do so.
// Thus utilizing JavaScript's inherit async behavior in a "pseudo"
// synchronous way.
if(i >= 2) clearTimeout(timer)
ParentFunc(i)
}
As a final note, though instantiating setTimeOut is common practice in mocking asynchronous behavior, when dealing with initial invocation/execution and all subsequent lifecycle timing of the methods intended to act as the event handlers, defer to utilizing Promises. Using Promises to resolve your event handlers ensures the timing of method(s) execution is relative to the scenario in which they are invoked and is not restricted to the rigid timing behavior defined in something like the "setTimeOut" approach.

Variable Scope with setTimeout & clearTimeout

While studying variable scope there has been one thing I can't seem to figure out. For example of two elements. If the first is hovered upon then its sibling appears. If you mouse-out of the initial element the sibling will disappear through a setTimeout which is stored within a variable expression. If you happened to hover over the sibling a clearTimeout function is called and is set to fade out in the callback.
In regards to scope what I'm not understanding is how exactly the timer variable is recognized in the clearTimeout function. I tried to console.log(timer) but just got numeric values. While the following works I'd like to know why and how? In other words how does the second hover method call know what's inside the timer variable since its out of scope?
var timer;
$('p:eq(1)').hide();
$('p').first().hover(function() {
$(this).next().fadeIn();
}, function() {
timer = setTimeout(function() {
$('p:eq(1)').fadeOut();
}, 1000);
// console.log(timer);
});
$('p:eq(1)').hover(function() {
clearTimeout(timer);
}, function() {
$('p:eq(1)').fadeOut(1000);
});
The function clearTimeout takes not just a setTimeout, but its ID. Here's what I found it on MDN:
So, when you set a timeout, it returns a specific ID for reference and so clearTimeout will work. Again, per MDN:
Since you set timer on the global scope, each of your functions has access to it.
Thanks for asking a question that taught me something! (I didn't know setTimeout returned anything)
Simple.. The timer itself is stored in memory though the 'timer' variable which you have defined in the same scope as the sibling event bindings. Therefore, the timer variable is acccessable by directly calling it with 'timer' in any sibling or child scopes. Had you declared the 'var timer' part within the function like this:
function() {
var timer;
timer = setTimeout(function() {
$('p:eq(1)').fadeOut();
}, 1000);
The result would be that clearTimeout(timer) would not be within the scope and result in an unknown member error.

Display markers one by one after 3 seconds using setTimeOut.. Why it shows only the last marker?

I am trying to display the markers one by one using setTimeOut but it is not working. here is my code:
function showOneByOne(arrayOfMarkersObj) {
for (u in arrayOfMarkersObj) {
setTimeout(function() {
arrayOfMarkersObj[u].setVisible(true);
}, 3000);
}
}
The problem is that It is showing only the last marker on the map and not all the markers. However if I put
arrayOfMarkersObj[u].setVisible(true);
outside of setTimeOut, It shows all markers.
Why is it happeneing?
Store the keys to an array (if you are solely on ECMA5 capable browsers you can use as suggested in comments the Object.keys() instead :
var keys = [];
for (u in arrayOfMarkersObj)
keys.push(u); //assuming arrayOfMarkersObj is an object not an array?
Now go one by one in your setTimeout:
var current = 0;
function reveal() {
arrayOfMarkersObj[keys[current++]].setVisible(true);
if (current < keys.length) setTimeout(reveal, 3000);
}
reveal();
If you want the first delayed switch the last line with:
setTimeout(reveal, 3000);
The reason why the example in the post doesn't work is because u is not available to setTimeout at the time it is called. The code invoked by the event setTimeout sets is invoked on the window object.
In order to make the var available you need to store it a "level up" typically the global scope or inside the wrapping function (by that = this for a reference as this becomes window, then use that inside setTimeout) to access it.
In JavaScript, the value of a variable in an inner scope is bound the scope where the variable is defined. Which means that the callback, when executed, will retrieve the value of u from the scope where u was defined, that is showOneByOne(). Therefore u will be equal to arrayOfMarkersObj.length -1 (the final value after the for cycle) for every execution of the callback.
One easy way to solve should be using forEach, even though it's not clear the need for different callbacks/timers for each element. You might as well use a single one as suggested in the answer by Ken - Abdias Software.

Why won't my timer increment the number?

I recently learned javascript. I was experimenting with it. Now, I tried to make a simple timer. Here is the code:
<html>
<head>
<script type="text/javascript">
function start(obj)
{
var t = setTimeout("increment(obj)", 1000);
}
function increment(obj)
{
obj.innerHTML = parseInt(obj.innerHTML) + 1;
start(obj);
}
</script>
</head>
<body>
<p onclick="start(this)">0</p>
</body>
</html>
The contents of the <p></p> should be incremented by 1 every second. Does anyone know why this doesn't work?
Because the string you pass into setTimeout is evaluated at global scope, not the scope within the function, and so doesn't refer to your obj object.
You should never pass strings to setTimeout. Instead, pass it a function reference:
function start(obj)
{
var t = setTimeout(function() {
increment(obj);
}, 1000);
}
function increment(obj)
{
obj.innerHTML = parseInt(obj.innerHTML) + 1;
start(obj);
}
The function we're passing to setTimeout is a closure, which means it has an enduring reference to the items in scope where it's defined. So a second later when the timer mechanism calls it, it still has access to the obj argument of your start function even though the start function has long since returned. More here: Closures are not complicated
The issue (or at least, the first that I see) is that you are passing the string "increment(obj)" to the setTimeout() method, but obj is only defined inside of your start() method. The string that you pass isn't actually evaluated until the timeout triggers, at which point no obj variable is in scope.
There are a few different ways around this. One is to pass a closure to setTimeout() instead of a JavaScript string, like:
function start(obj) {
var nextIncrement = function() {
increment(obj);
};
var t = setTimeout(nextIncrement, 1000);
}
Another (though less preferable) option is to promote obj to the global scope, like:
function start(obj) {
window.obj = obj;
var t = setTimeout("increment(obj)", 1000);
}
In general, however, you should avoid passing a string to setTimeout (and you should also avoid placing things in the global scope unnecessarily). As you have seen, it can cause issues with scope resolution, and for any non-trivial operation it also makes you code much less maintainable. Always prefer passing a function closure when possible.
Also, the following line of code is probably not doing exactly what you expect:
parseInt(obj.innerHTML)
You should always provide the radix argument to parseInt, to avoid errors with values such as 011 (which is 9, rather than 11, because it is evaluated in base-8 due to the leading 0). You can avoid these quirks by simply doing:
parseInt(obj.innerHTML, 10)
...to force a base-10 parse.
Anyways, working example here: http://jsfiddle.net/dSLZG/1
The problem is with this line of code:
var t = setTimeout("increment(obj)", 1000);
obj is an identifier in the functions scope -- it is only accessible within the start function. When you pass a string to setTimeout, it is evaluated in the global scope. This means that the obj variable is not available, so nothing is incremented.
You should pass a function object instead, as this will create a closure and your variable will be accessible:
function start(obj)
{
setTimeout(function() {
increment(obj);
}, 1000);
}
Note that I have removed the unnecessary var t =, because you're not doing anything with the timer identifier.
I've copied your code over to jsFidle and added a working example. See sample code.
The problem in your original version is that your variable obj is not defined in the global context. Whenever you pass strings to setTimeout you'll end up having the string evaluated in the global context (where obj is not a variable).
What you should do instead is never pass a string to setTimeout but a function object. This function object holds references to all variables that are set where the function object was defined.
So, because the function object passed to setTimeout in start2 is defined within start2 it has access to all variables and parameters of start2. Your variable obj is one of those and thus accessible within the function object as soon as it is executed by setTimeout.

Categories

Resources