Where I currently have the console logs, countdown seems to count down from 10 to 1 (this makes sense) but then after this, way seems to add 15 to the final result of countdown 9 times, but for this to happen, I'd imagine that after each countdown loop, way is called, but that each keeps track of its own value? Any clarification about the Why and When of this logic would be helpful - Thanks!
var countdown = function(value) {
value = value - 1;
if (value == 0) {
return value;
}
console.log("loop 1 " + value);
return way(countdown(value));
};
function way(value) {
value = value + 15;
console.log(value);
return value;
}
countdown(10);
As commented above value is a local variable in either function and thus always bound to the scope of either function. It doesn't actually contribute to confusion aside from expecting too much complexity there. ;)
The behaviour arises from countdown() being called recursively and calling way() has to wait until recursive calls for countdown() are returning. But that's not happening until countdown()'s recursion has stopped at value 0 to be returned eventually. After that countdown() isn't invoked ever again, but since countdown() was invoked recursively and this is bubbling up through all invocations of countdown() there are multiple calls for way() with the result returned from the countdown() called at end which in turn was calling way() with result of countdown() etc. ... ok, got a bit confused here myself.
Since value isn't required to be that complex it might help to eliminate it for reducing code:
function countdown(value) {
if ( value == 1 ) { return 0; } // bail out condition
console.log("loop 1 " + value)
return way( countdown( value - 1 ) );
};
function way( value ) {
console.log(value);
return value + 15;
}
countdown(10);
way() is of no relevance to the recursion and thus might be substituted:
function countdown(value) {
if ( value == 1 ) { return 0; } // bail out condition
console.log("loop 1 " + value)
return countdown( value - 1 ) + 15;
};
countdown(10);
Due to recursion this code is diving into stack 9 frames deep. And then it is bubbling up stack returning the result of every passed frame increased by another 15 prior to bubbling up further on.
So actually, there is only one recursion.
At first, the code starts executing your first call to countdown with argument value=10
Stack: []
Execute countdown(10)
Stack: [countdown(10)]
Then execute way(countdown(9)), and to execute this, JS first evaluates countdown(9)
Stack: [countdown(10), countdown(9), ] and so on, you can imagine, until you reach countdown(0), then start popping out from the stack call.
First stack call resolved, countdown(0) = 0, then call way(0), the console logs 0+15, then countdown(0) eventually returns 15, then pop from stack countdown(1) which is equal to way(countdown(0)), which is way(15), then prints out 30, and so on...
Hope this is clear enough
In order to understand this recursive code, it's easiest to follow the program counter:
function way (value) {
value=value +15
console.log(value)
return value
}
countdown = function(value) {
value = value-1
if (value == 0) {
return value;
}
console.log("loop 1 " + value)
return way(
countdown(value));
};
countdown(10);
Start countdown with 10
value > 0 so run way(countdown(9)) //note: countdown is executed first.
Countdown runs with 9
value > 0 so run way(countdown(8)) //note: countdown is executed first.
...
...
...
value == 0, return 0 (in countdown): execute way
way returns 0 + 15
way returns 15 + 15
way .... etc.
As fora clarification why this logic would be helpful; I think there is a lesson to be learned here.
Basically there are 2 relevant function-call positions when applying recursion:
positioned before recursive call
positioned after recursive call
I will leave it as an exercise of why this has any relevance.
Related
I want to make a continous counter. I mean, I want to close the page and in the other day open it and continue the counter from where I left.
Like, my counter did count 14235 times in one day. In another day I want it to continue from where I left (14235).
Code I made :
var a = 0; //// a is the "counter"
function count() { ///// function to count
chrome.storage.local.get(['a'], function(value) { return a = value.a;});
a += 1;
chrome.storage.local.set({"a": a}, function(){})
console.log(a)
setTimeout(count, 5000)
}
count()
I get 2 values in console.log, one from 0 and one from 14235, while I want get only one. Help.
Your questions is not getting well seen so I decided help you.
You cannot make a equal the last value, at least I cannot do it.
But you can do a better thing. Call it.
function count() {
if(a === 0){ chrome.storage.local.get(['b'], function(value) { return a = value.b }); } else { chrome.storage.local.set({"b": a}, function(){}) }
/// here, if a = 0 it will get the previous value but if a != 0 it will save the value :D
console.log(a)
setTimeout(count, 100)
a += 1;
}
count()
Hope see you again !
From this document, I understand that setTimeout returns an ID value of the timer.
But when I run this code:
for (var i = 1; i <= 5; i++) {
setTimeout(function() { console.log('hello'); }, 100);
}
I get the following in the console tab:
i.e. It printed the timer ID once and then 5 consecutive 'hello' instances.
Shouldn't the output have timerID, hello, timerID, hello, .... instead?
Why does setTimeout only print its ID once even if it is in the loop?
What you're seeing is due to the REPL (Read-Eval-Print Loop) nature of the Javascript console.
You're expecting to see the result of all the setTimeout() calls from each iteration of the loop. However, after finishing a set of statements, the JS console only prints out the return value of the most recently executed statement.
A simple display of this behavior:
Note: In these examples I'm depicting the JS console input/output instead of including executable code blocks, since the behavior being discussed is specific to interactively using the console.
> x = 4;
<- 4
> y = 5;
<- 5
> x; y;
<- 5
In the last command there are two statements, only the value of the last is printed.
If you want to print out the id's of each setTimeout() call, you just have to explicitly perform the logging action:
> for (var i = 1; i <= 5; i++) {
console.log(setTimeout(function() { console.log('hello'); }, 100));
}
596
597
598
599
600
<- undefined
5 hello
Above you see:
the 5 outputs from the immediately executed console.log(setTimeout(...)) statements
the undefined return value of the last console.log(setTimeout(...)) statement
the grouped output from the 5 delayed console.log('hello') statements
The reason why this is happening is because synchronous code. When you run the for loop, it is executing the setTimeout() 5 times and so you get the ID, and after 0.1 seconds (100 MS) it then executes its code. If you want to get it how you predicted (ID "Hello" ID "Hello" ... ) you would have to use await and an asynchronous function.
The function setTimeOut returns a value, so it is not displayed in the console, unless you assign a variable to it and then output the variable.
for (var i = 1; i <= 5; i++) {
let delay = setTimeout(function() { console.log(delay,'hello'); }, 100);
}
I was looking for Babylonian square root algorithm written in JavaScript, and found this working solution:
function sqrt(num) {
var accuracy = 0.000001;
function isPrecise(estimation) {
if (Math.abs( Math.pow(estimation, 2) - num ) < accuracy) {
return true
} else {
return false
}
}
function improvePrecision(estimation) {
return (estimation + (num / estimation)) / 2;
}
function iteration(estimation) {
if(isPrecise(estimation)) {
return estimation;
} else {
return iteration(improvePrecision(estimation));
}
}
return iteration(num);
}
But I can't see where is initial guess (in code - estimation) value is defined. So how it works, when there is no guess value on first iteration? Actually, this value should be eaqual to num argument.
The estimation is defined inside of the iteration function.
When the function runs the first time, the iteration function is called with the num parameter, return iteration(num).
Inside iteration function, the algorithm first checks if the estimation is ok.
If not, iteration is called again, but this time, it first improves the given estimation
return iteration(improvePrecision(estimation));
So iteration is recursive function, which will call itself unless the estimation is precise enough: (isPrecise(estimation))
Now i was reading at MDN functions section, and i was reading this example about recursion, which was:
function foo(i) {
if (i < 0) //1
return;
console.log('begin:' + i); //2
foo(i - 1); //3
console.log('end:' + i); //4
}
foo(3);
So what I would normally expect of calling the recursive function foo with an argument of 3 is that it goes to line 1 checks that condition which is at the beginning not gonna hold so it continues to line 2 and logs the ("begin: 3") then it goes to line 3 where recursion happens and that will make it go back to the line 1 and go through the same flow of processes, which should lead to ("begin: 2"), ("begin: 1"), ("begin: 0"), then it should stop so that it won't clog ("begin: -1"), that indeed happens in MDN example but somehow it logs is one more time but reversibly like this:
// Output:
// begin:3
// begin:2
// begin:1
// begin:0
// end:0
// end:1
// end:2
// end:3
My Questions:
in which sense after that (i = -1) and the function returns, the
function is not exiting the function and continue to line number 4?
how is (i) increasing again, i see no loop or recursion that is
increasing the value of (i) again so that it logging again from 0 to 3??
Here is what is happenning in your case :
// foo(3) called
console.log('begin:3');
foo(2)
console.log('begin:2');
foo(1)
console.log('begin:1');
foo(0)
console.log('begin:0');
foo(-1)
return;
console.log('end:0');
console.log('end:1');
console.log('end:2');
console.log('end:3');
1) When you have (i == -1), the function is actually exiting with the return, but then keep executing the code in the parents functions (see point 2) )
2) When you call foo(-1), you call return, so it means that you get back to your parent caller and keep executing the following code.
your function doesn't terminate before the result of the inner function call is there.
1) is the abort condition, it tells the function when to stop
2) its not increasing, its going further, because the result of the foo(i-1) call is there
Whenever a recursion occurs, the control perpetually remains at the top level. So although, the function goes through n number of inner levels, a return statement from one of the inner called functions would merely return to its immediate parent level.
In this case: i=3 was at the top level, then 2 and then 1 and then 0. As the return was fired at i=-1, it was bubbled back to its parent 0 level. The next return bubbled it up to its parent i=2 , and then i=3.
Do mark as answer if you're satisfied.
Your function does exactly what you have told it to do:
print begin:3
do everything that foo(3-1) does
print end:3
Every call to a function wait for it to finish before resuming to the next line. If it's the same function it's the same. The version of the function that calls is not intervened with the one it calls so they are separate as if they were separate functions
Imagine this function:
function foo(i) {
console.log('begin:' + i); //1
console.log('end:' + i); //2
}
Now the first console.log might be a recursive function. You don't know and shouldn't have to know. It does it's job and returns. You don't question why it continues to line 2 so I guess you give recursive function more mystery than it deserves.
function foo(i) {
if (i < 0){ //1
return;
}
console.log('begin:' + i); //2
function foo(i-1) {
if (i-1 < 0){ //3.3.1
return;
}
console.log('begin:' + i-1-1); //3.3.2
function foo(i-1-1) {
if (i-1-1 < 0){ //3.3.1
return;
}
console.log('begin:' + i-1-1); //3.3.2
function foo(((i-1) - 1)-1){}; //3.3.3
console.log('end:' + i-1-1); //3.3.4
}
console.log('end:' + i-1); //3.4
}
console.log('end:' + i); //4
}
foo(3)
Let's pretend i is alwyas 3!
This is what happens:
going into //2 and log 3
going into //3.2 and log 2
going into //3.3.2 and log 1
going into //3.3.3 and do the same stuff and log 0
going into imaginary //3.3.3.4 and log 0 because the parameter of //3.3.3 is 0
going into 3.3.4 and log 1
going into 3.4 and log 2
going into 4 and log 3
The code below allows me to have an array with a set of numbers such as "thearray=[2,8,9]" and loop through that array, and for each number item in the array for example "2,8,9", the code calls a function an amount of times equal to the current number item in the array. So if the current number item is 2, the function gets called twice.
After the set of calls, there is a pause, and then the function is called again an amount of times equal to the current number in the array etc. In other words, as the array is being looped through, if the current number item is 2, the function named "thefunction" will be called twice then there is a pause and the function "thefunction" is then again called an amount of times equal to the next number in the array.
In my case, "thefunction" simply displays an alert box message two times followed by a pause, then 8 times followed by a pause, then 9 times followed by a pause etc. Of course, with the alert box messages, I get the messages in sequence because I must select ok before I see the next alert message. The problem is, I can't get the calls to "thefunction" to appear sequential like when the code to be executed within "thefunction" displays an alert box, when other code such as appending an li item with data to a ul is within that function.
It's as if the 2 calls are made at once, then the 8 calls are made at once, etc. Even though that may not be the case, it happens so fast, it seems like it. I would like to slow it down. So if the code within "thefunction" was code that would append information to an li element, instead of just seeing the information rapidly added where the sequence of calls isn't noticeable, I would like there to be a delay so that when li elements are appended, the sequence is more obvious rather than rapid where it's hard to see the sequence.
Here is the code:
function runArray(arr, fn) {
// initialize array index - can't use for loop here with async
var index = 0;
function next() {
var cnt = +arr[index];
for (var i = 0; i < cnt; i++) {
fn(index, cnt);
}
// increment array index and see if there's more to do
++index;
if (index < arr.length) {
setTimeout(next, 400);
}
}
// start the whole process if the array isn't empty
if (arr.length) {
next();
}
}
runArray(thearray, shakeit);
and here is a jsfiddle demonstrating a log rapidly adding information. I want to slow it down so the information is added slow enough to make it obvious there is a sequence.
http://jsfiddle.net/jfriend00/Loycmb3b/
What you want to do in essence is insert a delay between executions of the for loop. The only sane way to introduce a delay in JavaScript is using setTimeout and setInterval, so that's what you have to work with.
The next thought is that since each loop iteration is to be implemented as a callback to setTimeout and friends, the logic that moves to the next array element after each loop completes is necessarily going to be part of that -- you can't move to the next element before the loop completes.
But the logic that moves to the next element is already inside next, and we already established that next is supposed to set up the callback. So next is going to schedule the callback, and the callback is also going to schedule next -- there's no other way.
Therefore:
function runArray(arr, fn, delay) {
var index = 0;
var cnt = 0;
var i = 0;
// Called once for each array element
function next() {
if (index >= arr.length) {
return;
}
cnt = +arr[index];
i = 0;
loop();
}
// Represents a single iteration of what was previously a for loop
// Will either schedule the next iteration or move to the next element
function loop() {
if (i < cnt) {
fn(index, i++);
setTimeout(loop, delay); // delay before next iteration
}
else {
++index;
setTimeout(next, delay); // delay before moving to next element
}
}
if (arr.length) {
next();
}
}
I kept the same delay both between "loop iterations" and between the end of a loop and the start of the next one, but that can easily be changed.
See it in action.
Unless I'm misunderstanding something...
function runArray(arr, fn, delay, idx, cnt) {
idx = idx || 0;
cnt = cnt || 0;
if(cnt >= arr[idx]) {
idx++;
cnt = 0;
}
if(idx >= arr.length)
return;
fn(idx, cnt);
setTimeout(function() { runArray(arr, fn, delay, idx, cnt + 1) }, delay);
}
http://jsfiddle.net/Loycmb3b/8/
I may or may not understand what you are trying to do, but with this piece of code here
runArray(theArray, theFunction, 400);
you are executing theArray and theFunction to occur after 400 ms, 1000 is one second, so if you want it to be a more substantial pause, increase that 400, here I increased it to 4000(4 seconds) and the pause is much more noticable.
http://jsfiddle.net/Loycmb3b/7/