weird behavior in javascript execution timing - javascript

i was a reading book named async javascript , one of the example of this book tried to show that events in javascript will trigger when processor has no instruction to do in the same process . for the proof of his word he brought an example :
for (var i = 1; i <= 3; i++) {
setTimeout(function(){ console.log(i); }, 0);
};
the output is :
4
4
4
4
everyhting is ok and i expected the result . but when i put the "console.log(i)" out of function the result will change .
for (var i = 1; i <= 3; i++) {
setTimeout(console.log(i), 0);
};
the output is :
1
2
3
i don't know why the output is different in those examples . i know its about variable scopes , but don't know exactly the reason . i hope if someone can help.

i don't know why the output is different in those examples
Because in the second case you are calling console.log(i) immediately and pass the return value undefined to setTimeout (instead of passing a function like in the first case).
Arguments are always evaluated first, so if you have foo(bar()), bar is called first and its return value is passed to foo.
You can verify this by adding console.log('after'); after the loop. In the first case, you should get
after
4
4
4
and in the second case, you will get
1
2
3
after
demonstrating that setTimeout is not adding anything to the event queue.
See also Calling functions with setTimeout()
i know its about variable scopes
Actually it's not, it's all about timing, the moment when console.log is executed.

When you call setTimeout(expr,t), expr gets evaluated, hoping it returns a function. In your second case console.log(...) doesn't return anything, but it gets evaluated nonetheless. What you see is the side-effect of this evaluation prior to passing the result to setTimeout.

Related

Why this ternary operator are not working ? is not ternary operator are functions?

I just learned about the ternary operator but it is not functioning like I expected. If find it really confusing. I get an error in the console over and over again, and I don't understand why.
A normal function gives me undefined, which is fine, but the ternary operator gives me a "not defined" error, but why?
Ternary Operator
var experiencePoints = winBattle() ? 10 : 1;
Error
VM363:1 Uncaught ReferenceError: winBattle is not defined
My function
function experiencePoints() {
if (winBattle()) {
return 10;
} else {
return 1;
}
}
And it gives:
undefined
I want to get undefined just like the normal function gives.
The error is not because you used the ternary operator.
The message is telling you that JavaScript cannot find a function named "winBattle()" anywhere in your code - or at least, not within the current scope.
As we will see in this demonstration, if you declare such a function, and make it return a simple boolean "true" value (just for example), then the error does not occur:
var experiencePoints = winBattle() ? 10 : 1;
console.log(experiencePoints);
function winBattle()
{
//I assume here you would have some logic to calculate the winner of the battle, and then return true or false depending on who won.
return true;
}
You will need to check the rest of your code, and either
a) create the function, if it doesn't exist
or
b) make it accessible from the scope where you are calling it. If you need help with this task, you will have to show us the rest of your code.
Here is some background information:
I think you may have mistaken the undefined you're seeing as the result of executing the "experiencePoints" function. It is not. It is simply the result of creating that function via the console. The console always shows the result of the line you just created, which in this case is nothing, because you're just declaring a function, not running anything which produces output. If you included that function in a web page you would not see such a message. You have never actually run that function. If you did (by writing experiencePoints();) you would almost certainly see the same error relating to winBattle(), since at the time you run the function, winBattle() does not exist.
The difference between that and your ternary operator code is that this line of code is not within a function, and is therefore executed immediately.
The two are not the same: the function experiencePoints only executes when it is called, but you are not calling it. Instead you enter the function definition itself which does not return anything, and so you see undefined in the console.
The variable assignment with the ternary operator is executed on-the-spot (it is not a function definition), and so winBattle must exist at that very moment. Apparently it doesn't, and so you get an error. If you would just do this:
var a = Math.random() > 0.5 ? 10 : 1
You will not get an error, because Math.random is defined. Also you will see undefined in the console, which is normal for a statement, like var.
Coming back to the function experiencePoints: you may wonder why you don't get the same error about winBattle there. It is because the function is not executed yet.
Until you actually call it, you still have time to define winBattle. If however you decide to call it without first defining winBattle, you will get that same error.
Now you can of course use a ternary operator in a function -- that would be a fair comparison. You can choose between several syntaxes. Here are two:
function experiencePoints {
return winBattle() ? 10 : 1;
}
or as arrow function with expression syntax:
var experiencePoints = () => winBattle() ? 10 : 1;
Again, here you would only get an error about winBattle when you call the function.

Display index of an array with a delay of 3 seconds

In the following code, I tried to keep timeout but it doesn't work. I am sending array and expecting array index with 3 sec delay.
function displayIndex(arr){ // array as input
for(var i=0;i<arr.length; i++){
SetTimeout(function(){
console.log(i); // always returns 4
},3000);
}
}
displayIndex([10,20,30,40])
update:
var arr = [10,20,30,40];
function displayIndex(arr){ // array as input
for(var i=0;i<arr.length; i++){
setTimeout(function () {
var currentI = i; //Store the current value of `i` in this closure
console.log(currentI);
}, 3000);
}
}
displayIndex(arr); // still prints all 4.
Also, tried
arr.forEach(function(curVal, index){
setTimeout(function(){
console.log(index);
},3000);
}); // prints 0 1 2 3 but I do not see 3 secs gap between each display, rather one 3 sec delay before everything got displayed.
Use this:
function displayIndex(arr){ // array as input
var i=0;
var current;
run=setInterval(function(){ // set function inside a variable to stop it later
if (i<arr.length) {
current=arr[i]; // Asign i as vector of arr and put in a variable 'current'
console.log(current);
i=i+1; // i increasing
} else {
clearInterval(run); // This function stops the setInterval when i>=arr.lentgh
}
},3000);
}
displayIndex([10,20,30,40]);
1st: If you use setTimeout or setInterval function inside a for that's a problem 'couse all this are loops ways (the first two are loops with time intervals). Aaand setTimeout just run code inside once.
Note: setInterval need a function to stop it clearInterval, so that's why i put an if inside.
2nd: You are not setting currentI or i like a vector of arr operator. When you run an array the format is: arr[currentI], for example.
Doubts?
SetTimeout should be setTimeout. It's case-sensitive.
You're setting 4 timeouts all at once. Since you're incrementing the value of i every loop, it's going to be 4 at the end of the loop.
I'm not really sure what you're trying to do, but perhaps you wanted this?
setTimeout(function () {
var currentI = i; //Store the current value of `i` in this closure
console.log(currentI);
}, 3000);
The reason why it's behaving unexpectedly:
Case 1: In the first snippet, setTimeout() is adding the functions to the Event Queue to be executed after main thread has no more code left to execute. The i variable was passed as reference and, so the last modified value gets printed on each call since, it was passed by reference.
Case 2: In this case, since you are passing 4 explicit references, the values are different but, the execution order will same ( I.e., synchronous and instantaneous).
Reason: setTimeout() function always pushes the function passed to the queue to be executed with the delay acting as a minimum guarantee that it will run with the delayed interval. However, if there is code in the queue before the function or, any other code in the main thread, the delay will be longer.
Workaround: If you do not to implement blocking behaviour in code, I would suggest using an analogue of process.hrtime() for browser ( there should be a timing method on the window object and, write a while loop that explicitly loops until a second has elapsed.
Suggestion: I am somewhat confused as to why you need such blocking in code?

flow of execution of javascript(synchronous or asynchronous)

Can someone explain me the behaviour of following code and javascript
for(var i = 0; i < 5; i++)
{
setTimeout(function(){
document.write('Iteration ' + i + ' <br>');
},1000);
}
document.write('DONE!');
why does it print 'DONE!' first?
Shouldn't it print all values of the loop and then print 'DONE!'?
why does it print 'DONE!' first? Shouldn't it print all values of the loop and then print 'DONE!'?
No, you've explicitly told it not to; instead, you've just created five functions and called setTimeout five times to give them to the browser to call later.
This code:
setTimeout(function(){
document.write('Iteration ' + i + ' <br>');
},1000);
calls the function setTimeout, passing in the function you see. That function is not called at that time. It's just created. setTimeout will call it later, as is its job. (And when it does, it will blow away the document, because calling document.write after the main parsing of the page is complete implicitly does document.open, which wipes out the previous document.)
So here's what happens with that code:
The variable i is created.
It's set to 0.
A function is created.
setTimeout is called with that function object's reference being passed in, along with the value 1000.
i is incremented.
Steps 2 through 5 repeat for values 1, 2, 3, and 4 of i.
document.write is called with the value 'DONE!'
About a second later, the browser calls the first function created in the loop.
That function calls document.write, which implicitly does a document.open, which blows away the existing document and replaces it with Iteration 5 <br> (yes, really 5).
The second function created in the loop is run, outputting the message again.
The remaining three functions are called, adding the message another three times.
The reason we see Iteration 5 five times instead of Iteration 0, then Iteration 1, etc., is that the functions have an enduring reference to the variable i, not to its value when they were created, so they all read its value later, as of when they run.
Javascript in normal is Synchronous Exectue line by line, but with code change you can act sometime as Asynchronous, but it's not actually going to execute on a separate thread.
Ok, what if you want to print Done just after the Document.write is done
length = 0;
for(var i = 0; i < 5; i++)
{
setTimeout(function(index){
console.log('Iteration ' + index + ' <br>');
length++;
callback();
}(i),1000);
}
function callback(){
if(length == 5)
console.log('DONE!');
}
What we did here is we increment the counter and try to call the callback after each time its incremented and when counter reach 5 that mean all the 5 functions is called and then we are able to print Done.
And as a side and important note, you was trying to print 0, 1, 2, 3, 4 but actually when you run your code it will give you 5, 5, 5, ,5, 5 because you write i and i at the point when you print is reached 5 and that's why it go out of the for loop, but you notice the code i added, i pass i as an argument to the function so that it will save the value for us and when time to execute the funtion it will write 0, 1, 2, 3, 4

Ractive and arrays, data not being updated

I'm learning how to use ractive and can't solve a problem, the code is at the following jsfiddle.
The gist of what I'm doing is counters for a queue (last object in array is current person):
1. A counter to display the queue number of the current person
2. A counter to display the size of the queue
A) works correctly but it is bloated with logic so I tried to convert it into a separate variable, as shown in B) but it doesn't update at all.
I put an observer in the code to watch when there is any change to the queue variable. I expect it to show an alert every time I click on "skip current person" or "delete current person" but the alert only shows up in the first time I load the page.
ractive.observe({
'queue.0.queueNo': alert('here')
});
Wim's answer is a good one - {{num(queue)}} is an elegant solution.
The reason you can't use queueNum is that when you do
queueNum = people[(people.length-1)].queueNo
the value of queueNum is set to whatever the value of people[(people.length-1)].queueNo is at the time of the statement. When the queue is altered, queueNum doesn't get re-evaluated. This isn't a Ractive thing so much as a JavaScript thing.
Another way of saying it is
a = 1;
b = 2;
foo = a + b; // foo === 3
a = 3;
b = 4;
alert( foo ); // alerts '3' - foo is the same, even though a and b changed
This is actually the same reason that the alert('here') was only triggering when the page loaded - rather than telling Ractive to trigger the alert when the value changed by wrapping it in a function, as in the second code block of Wim's answer, the code was executed immediately.
you can make queueNum a function based on queue like this:
num: function(q) { return q[(q.length-1)].queueNo;}
and call it like so: {{num(queue)}}
now when queue or people gets updated reactive knows it has to update num to. You don't even have to call ractive.update().
For the observe also make it a function and it will work:
ractive.observe({
'queue.0.queueNo': function(a,b) { alert('here');}
});

How are for loops executed in javascript?

I am at a loss how best to approach for loops in JavaScript. Hopefully an understanding of for loops will help shed light on the other types of loops.
Sample code
for (var i=0; i < 10; i=i+1) {
document.write("This is number " + i);
}
My understanding is that when i has been initialized, it starts with the value of 0 which then evaluated against the condition < 10. If it is less than 10, it the executes the statement document.write("This is number + i); Once it has executed the preceding statement, only then does it increment the next value by 1.
Guides I have consulted:
http://www.functionx.com/javascript/Lesson11.htm
http://www.cs.brown.edu/courses/bridge/1998/res/javascript/javascript-tutorial.html#10.1
http://www.tizag.com/javascriptT/javascriptfor.php
Now the guide at http://www.functionx.com/javascript/Lesson11.htm seems to indicate otherwise i.e.
To execute this loop, the Start condition is checked. This is usually
the initial value where the counting should start. Next, the Condition
is tested; this test determines whether the loop should continue. If
the test renders a true result, then the Expression is used to modify
the loop and the Statement is executed. After the Statement has been
executed, the loop restarts.
The line that throws me is "If the test renders a true result, then the Expression is used to modify the loop and the Statement is executed". It seems to imply that because 0 is less than 10, increment expression is modified which would be 0 + 1 and THEN the statement, e.g. document.write is executed.
My problem
What is the correct way to interpret for loops? Is my own comprehension correct? Is the same comprehension applicable to other programming languages e.g. PHP, Perl, Python, etc?
Think of a for loop as the following
for(initializers; condition; postexec) {
execution
}
When the loop is first started the code var i = 0 is run. This initializes the variable that you will be testing for inside the loop
Next the loop evaluates the i < 10 expression. This returns a boolean value which will be true for the first 10 times it is run. While this expression keeps evaluating to true the code inside the loop is run.
document.write("This is number " + i);
Each time after this code is run the last part of the loop i++ is executed. This code in this example adds 1 to i after each execution.
After that code is executed the condition of the loop is check and steps 2 and 3 repeat until finally the condition is false in which case the loop is exited.
This the way loops work in the languages you mentioned.
Lets have a look at the corresponding section in the ECMAScript specification:
The production
IterationStatement : for ( var VariableDeclarationListNoIn ; Expressionopt ; Expressionopt) Statement
is evaluated as follows:
1. Evaluate VariableDeclarationListNoIn.
2. Let V = empty.
3. Repeat
a. If the first Expression is present, then
i. Let testExprRef be the result of evaluating the first Expression.
ii. If ToBoolean(GetValue(testExprRef)) is false,
return (normal, V, empty).
b. Let stmt be the result of evaluating Statement.
...
f. If the second Expression is present, then
i. Let incExprRef be the result of evaluating the second Expression.
ii. Call GetValue(incExprRef). (This value is not used.)
As you can see, in step 1, the variable assignment is evaluated. In step 3a, the condition is tested. In step 3b, the loop body is evaluated, and after that the third expression is evaluated in step 3f.
Therefore your understanding of the for loop is correct.
It is to assume that it works the same way in other languages, since the for loop is such a common statement in programming languages (note that Python does not have such a statement). But if you want to be absolutely certain, you better consult their specification as well.
Your quoted source is wrong, and we can prove it...
The basis of the for loop has four separate blocks which may be executed:
for(initialise; condition; finishediteration) { iteration }
Fortunately we can execute a function in each of these blocks. Therefore we can create four functions which log to the console when they execute like so:
var initialise = function () { console.log("initialising"); i=0; }
var condition = function () { console.log("conditioning"); return i<5; }
var finishediteration = function () { console.log("finished an iteration"); i++; }
var doingiteration = function () { console.log("doing iteration when `i` is equal", i); }
Then we can run the following, which places the above functions into each block:
for (initialise(); condition(); finishediteration()) {
doingiteration();
}
Kaboom. Works.
If you viewing this page using Safari on the Mac then you can AppleAlt + I and copy the above two snippets, in order, into the console and see the result.
EDIT, extra info....
Also... the finished iteration block is optional. For example:
for (var i=0; i<10;) {
console.log(i); i++;
};
does work.
The second reference is wrong. Your explanation is correct.
Another way to think about it, if this helps you:
var i = 0;
while (i < 10) {
document.write("This is number " + i);
i++;
}
This is for statement syntax:
for(initalize, condition, increment) {
Do_some_things();
}
initalize Will executed only one time when for begin then it execute Do_some_things(); statement, and while condition still true it will execute increment and then Do_some_things();. if co condition false, for would exit.
for (var i=0; i < 10; i=i+1) {
document.write("This is number " + i);
}
var i=0 will execute one time (initalize).
i < 10 condition was always checked after a loop.
i=i+1 will execute after check i < 10 and result is true.
Value of i is: 0, 1, 3, 4, 5, 6, 7, 8, 9 (10 times loop)

Categories