Trying to understand the differences across these promises and setTimeouts [duplicate] - javascript

I have this counter I made but I want it to run forever, it's really simple, what am I doing wrong here?
function timer() {
console.log("timer!")
}
window.setInterval(timer(), 1000)

You used a function call instead of a function reference as the first parameter of the setInterval. Do it like this:
function timer() {
console.log("timer!");
}
window.setInterval(timer, 1000);
Or shorter (but when the function gets bigger also less readable):
window.setInterval( function() {
console.log("timer!");
}, 1000)

setInterval and setTimeout must be used with callbacks, like:
setInterval(timer, 1000);
or unnamed functions:
setInterval( function() { console.log("timer!"); }, 1000 );
Why your code is not working - when you pass a function as argument to another function with brackets e.g. doSomething ( someFunc() ) you are passing the result of the function.
When the function is passed as object e.g. doSomething ( someFunc ) you are passing a callback. This way someFunc is passed as reference and it is executed somewhere in the calling function. This is the same as the pointers to functions in other languages.
A common mistake is to use the these two functions as shown at w3schools. This makes an implicit call to eval.

Related

ES6 Arrow functions vs ES5: how to know which function to bind `this` to when using ES5 non-arrow function

I'm reading this article on using ES6 arrow functions. It gives the following example, where you have to use bind(this), followed by the corresponding code with arrow functions.
var obj = {
id: 42,
counter: function counter() {
setTimeout(function() {
console.log(this.id);
}.bind(this), 1000);
}
};
It says In the ES5 example, .bind(this) is required to help pass the this context into the function.
What I Want To Know: Why do you use bind(this) with the callback to setTimeout rather than with the counter function? ie why isn't the above code like this:
var obj = {
id: 42,
counter: function counter() {
setTimeout(function() {
console.log(this.id);
}, 1000);
}.bind(this);
};
Why do you use bind(this) with the callback to setTimeout rather than with the counter function?
Because the counter function (which works like a method of the obj object) already has the proper this because you call it like obj.counter() so it gets this from calling it as obj.counter(). Assuming you call counter as obj.counter(), then if you do console.log(this.id) on the first line of the counter() function, it will properly show the id value.
The callback you pass to setTimeout() however has no natural this value unless you use an arrow function or .bind() on the callback function itself because when setTimeout() calls your callback it does not set a specific this value (it just calls your callback as a normal function), therefore the this value goes to the default. That means this will be undefined if running strict mode or the global object if running in loosey-goosey mode inside of the setTimeout() callback.
See the 6 ways that the value of this is set here when calling a function.
I should also mention that if you did what you were proposing like this:
var obj = {
id: 42,
counter: function counter() {
setTimeout(function() {
console.log(this.id);
}, 1000);
}.bind(this);
};
Not only would it not help the setTimeout() callback at all, but it would also bind the wrong value of this to the counter() method. You would get whatever this was before the var obj definition (also known as the lexical value of this).

Attempting to generate HTML in vanilla JS using document.write, then access the tags using .getElementById [duplicate]

I need to run a javascript function each 10 seconds.
I understand the syntax must work like follow but I am not getting any success:
function funcName() {
alert("test");
}
var func = funcName();
var run = setInterval("func",10000)
But this isn't working. Any help?
A lot of other answers are focusing on a pattern that does work, but their explanations aren't really very thorough as to why your current code doesn't work.
Your code, for reference:
function funcName() {
alert("test");
}
var func = funcName();
var run = setInterval("func",10000)
Let's break this up into chunks. Your function funcName is fine. Note that when you call funcName (in other words, you run it) you will be alerting "test". But notice that funcName() -- the parentheses mean to "call" or "run" the function -- doesn't actually return a value. When a function doesn't have a return value, it defaults to a value known as undefined.
When you call a function, you append its argument list to the end in parentheses. When you don't have any arguments to pass the function, you just add empty parentheses, like funcName(). But when you want to refer to the function itself, and not call it, you don't need the parentheses because the parentheses indicate to run it.
So, when you say:
var func = funcName();
You are actually declaring a variable func that has a value of funcName(). But notice the parentheses. funcName() is actually the return value of funcName. As I said above, since funcName doesn't actually return any value, it defaults to undefined. So, in other words, your variable func actually will have the value undefined.
Then you have this line:
var run = setInterval("func",10000)
The function setInterval takes two arguments. The first is the function to be ran every so often, and the second is the number of milliseconds between each time the function is ran.
However, the first argument really should be a function, not a string. If it is a string, then the JavaScript engine will use eval on that string instead. So, in other words, your setInterval is running the following JavaScript code:
func
// 10 seconds later....
func
// and so on
However, func is just a variable (with the value undefined, but that's sort of irrelevant). So every ten seconds, the JS engine evaluates the variable func and returns undefined. But this doesn't really do anything. I mean, it technically is being evaluated every 10 seconds, but you're not going to see any effects from that.
The solution is to give setInterval a function to run instead of a string. So, in this case:
var run = setInterval(funcName, 10000);
Notice that I didn't give it func. This is because func is not a function in your code; it's the value undefined, because you assigned it funcName(). Like I said above, funcName() will call the function funcName and return the return value of the function. Since funcName doesn't return anything, this defaults to undefined. I know I've said that several times now, but it really is a very important concept: when you see funcName(), you should think "the return value of funcName". When you want to refer to a function itself, like a separate entity, you should leave off the parentheses so you don't call it: funcName.
So, another solution for your code would be:
var func = funcName;
var run = setInterval(func, 10000);
However, that's a bit redundant: why use func instead of funcName?
Or you can stay as true as possible to the original code by modifying two bits:
var func = funcName;
var run = setInterval("func()", 10000);
In this case, the JS engine will evaluate func() every ten seconds. In other words, it will alert "test" every ten seconds. However, as the famous phrase goes, eval is evil, so you should try to avoid it whenever possible.
Another twist on this code is to use an anonymous function. In other words, a function that doesn't have a name -- you just drop it in the code because you don't care what it's called.
setInterval(function () {
alert("test");
}, 10000);
In this case, since I don't care what the function is called, I just leave a generic, unnamed (anonymous) function there.
Change setInterval("func",10000) to either setInterval(funcName, 10000) or setInterval("funcName()",10000). The former is the recommended method.
That's because you should pass a function, not a string:
function funcName() {
alert("test");
}
setInterval(funcName, 10000);
Your code has two problems:
var func = funcName(); calls the function immediately and assigns the return value.
Just "func" is invalid even if you use the bad and deprecated eval-like syntax of setInterval. It would be setInterval("func()", 10000) to call the function eval-like.
Try this:
function funcName() {
alert("test");
}
var run = setInterval(funcName, 10000)
Btw this didn't work
setInterval(function () {
alert("test");
}, 10000);
I had to give a name (whatever you like) to the anonymous function:
setInterval(function alertNotification () {
alert("test");
}, 10000);

Javascript: setTimeout beahavior in this example [duplicate]

Simply put...
why does
setTimeout('playNote('+currentaudio.id+', '+noteTime+')', delay);
work perfectly, calling the function after the the specified delay, but
setTimeout(playNote(currentaudio.id,noteTime), delay);
calls the function playNote all at the same time?
(these setTimeout()s are in a for loop)
or, if my explanation is too hard to read, what is the difference between the two functions?
The first form that you list works, since it will evaluate a string at the end of delay. Using eval() is generally not a good idea, so you should avoid this.
The second method doesn't work, since you immediately execute a function object with the function call operator (). What ends up happening is that playNote is executed immediately if you use the form playNote(...), so nothing will happen at the end of the delay.
Instead, you have to pass an anonymous function to setTimeout, so the correct form is:
setTimeout(function() { playNote(currentaudio.id,noteTime) }, delay);
Note that you are passing setTimeout an entire function expression, so it will hold on to the anonymous function and only execute it at the end of the delay.
You can also pass setTimeout a reference, since a reference isn't executed immediately, but then you can't pass arguments:
setTimeout(playNote, delay);
Note:
For repeated events you can use setInterval() and you can set setInterval() to a variable and use the variable to stop the interval with clearInterval().
You say you use setTimeout() in a for loop. In many situations, it is better to use setTimeout() in a recursive function. This is because in a for loop, the variables used in the setTimeout() will not be the variables as they were when setTimeout() began, but the variables as they are after the delay when the function is fired.
Just use a recursive function to sidestep this entire problem.
Using recursion to deal with variable delay times:
// Set original delay
var delay = 500;
// Call the function for the first time, to begin the recursion.
playNote(xxx, yyy);
// The recursive function
function playNote(theId, theTime)
{
// Do whatever has to be done
// ...
// Have the function call itself again after a delay, if necessary
// you can modify the arguments that you use here. As an
// example I add 20 to theTime each time. You can also modify
// the delay. I add 1/2 a second to the delay each time as an example.
// You can use a condition to continue or stop the recursion
delay += 500;
if (condition)
{ setTimeout(function() { playNote(theID, theTime + 20) }, delay); }
}
Try this.
setTimeout(function() { playNote(currentaudio.id,noteTime) }, delay);
Don't use string-timeouts. It's effective an eval, which is a Bad Thing. It works because it's converting currentaudio.id and noteTime to the string representations of themselves and hiding it in the code. This only works as long as those values have toString()s that generate JavaScript literal syntax that will recreate the value, which is true for Number but not for much else.
setTimeout(playNote(currentaudio.id, noteTime), delay);
that's a function call. playNote is called immediately and the returned result of the function (probably undefined) is passed to setTimeout(), not what you want.
As other answers mention, you can use an inline function expression with a closure to reference currentaudio and noteTime:
setTimeout(function() {
playNote(currentaudio.id, noteTime);
}, delay);
However, if you're in a loop and currentaudio or noteTime is different each time around the loop, you've got the Closure Loop Problem: the same variable will be referenced in every timeout, so when they're called you'll get the same value each time, the value that was left in the variable when the loop finished earlier.
You can work around this with another closure, taking a copy of the variable's value for each iteration of the loop:
setTimeout(function() {
return function(currentaudio, noteTime) {
playNote(currentaudio.id, noteTime);
};
}(currentaudio, noteTime), delay);
but this is getting a bit ugly now. Better is Function#bind, which will partially-apply a function for you:
setTimeout(playNote.bind(window, currentaudio.id, noteTime), delay);
(window is for setting the value of this inside the function, which is a feature of bind() you don't need here.)
However this is an ECMAScript Fifth Edition feature which not all browsers support yet. So if you want to use it you have to first hack in support, eg.:
// Make ECMA262-5 Function#bind work on older browsers
//
if (!('bind' in Function.prototype)) {
Function.prototype.bind= function(owner) {
var that= this;
if (arguments.length<=1) {
return function() {
return that.apply(owner, arguments);
};
} else {
var args= Array.prototype.slice.call(arguments, 1);
return function() {
return that.apply(owner, arguments.length===0? args : args.concat(Array.prototype.slice.call(arguments)));
};
}
};
}
I literally created an account on this site to comment on Peter Ajtai's answer (currently highest voted), only to discover that you require 50 rep (whatever that is) to comment, so I'll do it as an answer since it's probably worth pointing out a couple things.
In his answer, he states the following:
You can also pass setTimeout a reference, since a reference isn't executed immediately, but then you can't pass arguments:
setTimeout(playNote, delay);
This isn't true. After giving setTimeout a function reference and delay amount, any additional arguments are parsed as arguments for the referenced function. The below would be better than wrapping a function call in a function.
setTimeout(playNote, delay, currentaudio.id, noteTime)
Always consult the docs.
That said, as Peter points out, a recursive function would be a good idea if you want to vary the delay between each playNote(), or consider using setInterval() if you want there to be the same delay between each playNote().
Also worth noting that if you want to parse the i of your for loop into a setTimeout(), you need to wrap it in a function, as detailed here.
It may help to understand when javascript executes code, and when it waits to execute something:
let foo2 = function foo(bar=baz()){ console.log(bar); return bar()}
The first thing javascript executes is the function constructor, and creates a function object. You can use either the function keyword syntax or the => syntax, and you get similar (but not identical) results.
The function just created is then assigned to the variable foo2
At this point nothing else has been run: no other functions called (neither baz nor bar, no values looked up, etc. However, the syntax has been checked inside the function.
If you were to pass foo or foo2 to setTimeout then after the timeout, it would call the function, the same as if you did foo(). (notice that no args are passed to foo. This is because setTimeout doesn't by default pass arguments, although it can, but those arguments get evaluated before the timeout expires, not when it expires.)
After foo is called, default arguments are evaluated. Since we called foo without passing arguments, the default for bar is evaluated. (This would not have happened if we passed an argument)
While evaluating the default argument for bar, first javascript looks for a variable named baz. If it finds one, it then tries to call it as a function. If that works, it saves the return value to bar.
Now the main body of the function is evaluated:
Javascript looks up the variable bar and then calls console.log with the result. This does not call bar. However, if it was instead called as bar(), then bar would run first, and then the return value of bar() would be passed to console.log instead. Notice that javascript gets the values of the arguments to a function it is calling before it calls the function, and even before it looks up the function to see if it exists and is indeed a function.
Javascript again looks up bar, and then it tries to call it as a function. If that works, the value is returned as the result of foo()
So, function bodies and default arguments are not called immediately, but everything else is. Similarly, if you do a function call (i.e. ()), then that function is executed immediately as well. However, you aren't required to call a function. Leaving off the parentheses will allow you to pass that function around and call it later. The downside of that, though, is that you can't specify the arguments you want the function to be called with. Also, javascript does everything inside the function parentheses before it calls the function or looks up the variable the function is stored in.
Because the second one you're telling it to call the playNote function first and then pass the return value from it to setTimeout.

How exactly works the setTimeout() JavaScript method?

I am not so into JavaScript and I have the following doubt related the setTimeout() method.
So into a test script I have:
function simpleMessage() {
alert("This is just an alert box");
}
// settimeout is in milliseconds:
setTimeout(simpleMessage, 5000);
So when I perform the page, after 5 second the simpleMessage() function is performed and it is shown the alert popup.
I understand that when I do:
setTimeout(simpleMessage, 5000);
it means that the simpleMessage() function have to be performed after 5 second after the timer settings but why it is used simpleMessage and not simpleMessage() for the function invocation?
simpleMessage is a reference to a function whereas simpleMessage() executes the function. setTimeout needs a function reference to call a later time.
To perhaps make things a little more obvious, you could have written your function declaration as
// define my function (but don't execute it)
var myFunction = function() {
alert('SOUND THE ALARMS!');
};
// start a timer that will execute the given function after the given
// period of time
setTimeout(myFunction, 5000);
See setTimeout documentation.
The first argument to setTimeout is the function to be executed. The identifier simpleMessage refers to the function you want setTimeout to execute, so that's what you supply as an argument to setTimeout.
If you did setTimeout(simpleMessage(), 5000);, you would execute simpleMessage immediately and then setTimeout would get the return value as its first argument. This is comparable to:
var value = simpleMessage();
setTimeout(value, 5000);
This doesn't make sense; it is the same as setTimeout(simpleMessage(), 5000);.
Consider also a higher-order function that returns a function:
function funcFacotry() {
return function() { alert("this is just an alert box."); }
}
var simpleMessage = funcFactory();
setTimeout(simpleMessage, 5000);
In this case, this actually does make sense, because the return value of funcFactory is actually a function itself.
setTimeout in javascript executes the function after a specific amount of time set as the second parameter, while if you use with setInterval it will execute in intervals, without to consider if the function is get executed or not (this will lead to chunkiness for example if you ar using for animation).
As a metter of second question: if you are using the function with parentheses, this is a method invocation, while using without parentheses is a reference to a specific method.
Because you need to pass a reference to setTimeout of the function you want to invoke after the 5s.
This:
setTimeout(simpleMessage(), 5000);
would execute the simpleMessage function at the same time you're calling the setTimeout function.

JavaScript - SetInterval doesn't function properly

I got this piece of script (runned locally):
<script>
last = 0;
function uploadnew(){
var randomnumber=Math.floor(Math.random()*6);
if(randomnumber != last){
document.forms['f'+randomnumber].submit();
} else { uploadnew(); }
}
setInterval (uploadnew(), 1000*60*5);
</script>
But it seems that setInterval is not working / send form function doesn't work...
Any help will be appreciated!
Thanks!
You need to call setInterval() without parenthesis on your function, like this:
setInterval(uploadnew, 1000*60*5);
Using parenthesis you're calling it immediately and assigning the result (undefined) to be run on an interval, instead don't use parenthesis to pass the function itself, not the result of the function.
You need to remove the () after uploadnew within the setInterval call:
setInterval (uploadnew, 1000*60*5);
In JavaScript, functions are first-class objects which can be passed to other functions. In this example, you want to pass the function itself to setInterval, not call it first and then pass its return value.
Using setInterval ("uploadnew()", 1000*60*5); is not recommended because it is a "hidden" form of eval. Eval is evil and you shouldn't use it if you don't have to.
You need to pass a reference to the function instead of calling it.
This:
setInterval (uploadnew(), 1000*60*5);
should be:
setInterval (uploadnew, 1000*60*5);
If you were to call it as you were, you would need to have uploadnew() return a function to be passed to setInterval.
function uploadnew() {
return function(){
var randomnumber=Math.floor(Math.random()*6);
if(randomnumber != last) {
document.forms['f'+randomnumber].submit();
} else { uploadnew()(); }
}
}
Note the change to the recursive call.
Use
setTimeout ( expression, timeout );

Categories

Resources