During studying JS, the following code is mysterious to me.
The following code never print out 'this is fn'?
I am not sure fn=null; is always called first before callback function of
setTimtout(..,0)
function fn(){
console.log('this is fn');
}
var intv = setTimeout( function(){
intv = null;
if (fn) fn();
}, 0 );
fn = null;
Because this is how it will work. The callback function of setTimeout will be pushed in the queue until the stack gets empty.
The stack will get empty after the assignment fn = null;.
Now the event loop will push the callback to stack as it will be empty and hence it will execute and as the fn is not a function anymore but null so will not do any console.log.
A timeout will not run the function until:
The timeout has passed
The minimum timeout has passed
The event loop isn't busy running some other code
So you:
Define a function
Define a timeout
Set fm to null
At this stage the event loop stops being busy.
If the minimum timeout hasn't passed, then JS waits a bit.
Then the function gets called.
fn is null.
You need to understand how JavaScript execute any function. The datastrcture is called as Call Stack
Call Stack :- It’s a data structure which records the function calls, basically where in the program we are. If we call a function to
execute , we push something on to the stack, and when we return from a
function, we pop off the top of the stack.
Here in your case the complete script itself is first call we can call it main.
So first entry in stack is,
function fn(){
console.log('this is fn');
}
var intv = setTimeout( function(){
intv = null;
if (fn) fn();
}, 0 );
fn = null;
In that code the set timeout is second call after the first entry executed.
var intv = setTimeout( function(){
intv = null;
if (fn) fn();
}, 0 );
Now JavaScript call stack will execute the first entry which sets the value to fn to null at last line.
Then it will execute the timeout interval function where fn is null. Where if (fn) will return false and nothing will be executed at all.
Related
let x = 0;
function a() {
console.log("called a()");
for (let i=0; i<123456789; ++i) {
x += Math.sqrt(2);
}
console.log("x = "+x);
}
function b() {
x = undefined;
console.log("called b()");
}
setTimeout(b, 20);
a();
output:
called a()
x = 174594265.7306214
called b()
b should have been called sooner, but it waited until the function a completed.
I know js uses only one thread, but the processor could have switched between executing a and b during a's execution. Does the processor always execute only one function at a time (if there is no await inside)? In nodejs and in website javascript?
EDIT:
Here is an await example:
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
let x = 0;
async function a() {
console.log("called a()");
await sleep(1000);
for (let i=0; i<123456789; ++i) {
x += Math.sqrt(2);
}
console.log("x = "+x);
}
function b() {
x = undefined;
console.log("called b()");
}
setTimeout(b, 20);
a();
output:
called a()
called b()
x = NaN
notice how x becomes NaN, since b is executed during a
b should have been called sooner, but it waited until the function a
completed.
No. b should be called after your synchronous code has executed because that's when a function passed to setTimeout is called.
Callback function of setTimeout is scheduled to run after the delay you specify as a second argument to setTimeout. This delay is the minimum amount of time it will take to run the callback function scheduled using setTimeout.
Once the timer expires, that callback function is put in a task queue and from there it is pushed to the call stack BUT it is only pushed once the call stack is empty.
In your case, call stack will be empty when your script has finished its execution.
I know js uses only one thread, but the processor could have switched
between executing a and b during a's execution
That's not possible with only 1 thread. In Javascript, only one thing executes at a given time, unless you use another thread.
Does the processor always execute only one function at a time (if
there is no await inside)
Yes. Even with await, function is paused until the promise is settled. Once the promise settles, that function continues execution and at that time, nothing else executes.
Edit
notice how x becomes NaN, since b is executed during a
No, there is no interference here. Function a is executed synchronously until the following statement
await sleep(1000);
While the function a is paused, waiting for the promise returned by sleep(...) to settle, during this time, function b is executed because its timer has expired and the call stack is empty.
Since both functions assign to same variable x, value of x is NaN because its value before function a resumes is undefined and performing addition on undefined leads to NaN.
This question already has answers here:
Why is the method executed immediately when I use setTimeout?
(8 answers)
Closed 1 year ago.
const eventLoop = () => {
console.log("Start");
setTimeout(() => console.log("Settimeout"), 0)
console.log("End");
}
eventLoop();
Output:
Start
End
Settimeout
But for
const eventLoop = () => {
console.log("Start");
setTimeout(console.log("Settimeout"), 0)
console.log("End");
}
eventLoop();
Output:
Start
Settimeout
End
Please help me to understand JS execution stack and event loop in above scenario
Have you executed console.log() inside developer tools?
I think it was very confusing at first time. it has many relationship with this question.
console.log("Hello, World!");
// returns undefined
It's a kind of expression returns undefined with side effect.
const eventLoop = () => {
console.log("Start");
setTimeout(console.log("Settimeout"), 0)
console.log("End");
}
eventLoop();
console.log("Settimeout") expression in above code is executed immediately, before setTimeout function called.
Therefore, it is not related with event loop.
const eventLoop = () => {
console.log("Start");
setTimeout(() => console.log("Settimeout"), 0)
console.log("End");
}
eventLoop();
In this example you :
console.log is put on function call stack, since stack is empty it is executed.
The function passed to setTimeout is added to the tasks queue. The thing to note here is that the delay will be atleast 0ms and it is not guaranteed that the function will be called after 0ms.
Now this console.log is called using the stack.
Now, since the stack is empty and the execution has completed items from the queue are picked. So the function passed in step 2 is picked and called.
const eventLoop = () => {
console.log("Start");
setTimeout(console.log("Settimeout"), 0)
console.log("End");
}
eventLoop();
In this example, step 1 and 3 are exactly same as example#1. But, in step 2 you are not passing any function inside setTimeout you are simply calling console.log() there.
() => console.log("Settimeout") is not the same as console.log("Settimeout").
First becomes ->
() => {
return console.log("Settimeout");
}
Second is simply, console.log("Settimeout").
In short, when in second example execution reaches line 2, console.log() is executed. But in first example, a function is passed to setTimeout which has the responsibility of calling console.log().
The following URL explains very well the event loop.
https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/
This one explains what parameters receives the SetTimeOut function
https://www.w3schools.com/jsref/met_win_settimeout.asp
When you use the function in the first of your cases, the function passed as parameter is called after the next cycle in the event loop, it means you have to pass a function to be called after the cycle, but if you put "console.log" you are performing that function instantly, so there is no function to be called in the next cycle.
I am a bit confused about setTimeout.I want to confirm whether the output for the following code will always be:
inside abc
inside sample
The code:
function abc() {
xyz();
// interactions and modifications in DOM
$("#id1").append("something");
$("#id2").val("set something");
$("#id3").after("create some dynamic element");
// 10 to 20 interaction more...
console.log('inside abc');
}
function xyz() {
setTimeout(function() {
sample();
},0);
}
function sample() {
console.log('inside sample')
}
It would be great,if somebody could explain the whole flow with the call stack.
Yes, it will always have that output.
The callback inside a setTimeout will not be called until the execution context is clear - i.e. the currently executing sequence of code has finished.
This means that even if you do
setTimeout(function () { console.log("1 second!"); }, 1000);
var start = +new Date();
while ((+new Date()) - start < 5000) {}
1 second! will not be logged any sooner than 5 seconds have passed.
setTimeout() will run asynchronously after finishing current execution block. So output should be same always:
inside abc
inside sample
Javascript internally manage an event queues internally for all async tasks. Every time it checks its async queue after finishing current execution block.
Yes, the console output will always be the same. setTimeout's callback function is executed asynchronously after the context that called it is cleared. When setTimeout is called, it places its callback function on the stack and returns to the current execution context. When that is done (in your example, when abc is fully executed), the callback function is executed, which in your example basically calls sample immediately. So your code output will never be different.
The fact that setTimeout's callbacks are themselves executed asynchronously can be seen if you placed a longer setTimeout function somewhere inside abc before calling xyz:
function abc() {
setTimeout(function(){
console.log('wait')
},1000);
xyz();
console.log('inside abc');
}
function xyz() {
setTimeout(function(){
sample();
} ,0);
}
function sample() {
console.log('inside sample');
}
abc();
...your console will log:
inside abc
inside sample
wait
To hold sample's execution until the longer timeout is complete you would need to place the setTimeout calling sample inside the longer setTimeout.
If setTimeout's callback is ever behaving differently, it's most likely due to being accidentally passed a function call instead of a function pointer, like this:
setTimeout(sample(),0);
instead of
setTimeout(sample,0)
Also, just in case you didn't know (or for others), you can add
debugger;
at any point(s) in your Javascript code and then run the code to view the callstack at that point using dev tools (in Chrome it is in the right panel under 'Sources').
I have the following function which cannot be run concurrently:
function foo()
{
if(this.running) return;
this.running = true;
setTimeout(function() {
// Do Something
delete this.running;
}, 5000);
}
The above seems to work, but when I check the value of this within the anonymous function, it is pointing to Window. I am not sure if this is proper or correct method to delete the property. Can anyone advise why this is working?
Yes that is correct because the object that invokes the anonymous function you provided in the setTimepout is the window object, to save a closure variable with the value of this just do the following:
function foo()
{
if(this.running) return;
this.running = true;
var self=this;
setTimeout(function() {
// Do Something
delete self.running;
}, 5000);
}
Update:
When you run foo function that was executed from X object (has X as this), it invokes the content of the function sequentially until it runs setTimeout function, this function adds the anonymous function under the sleep queue the execution will continue executing the foo function with X object,
when each element in the sleep queue passes his timeout time, it will be invoked under the window object for all of them.
I have an array of functions to iterate with setTimeout function to give non-blocking effects, but any or all function can have order flag, which means this is to be executed only after previous functions have been executed. Someone suggested me to use jquery.deferred. I've never used jquery deferred.
while(that.funcns.length>0){
fn=that.funcns.splice(0,1)[0];
fn.idx=i;
window.setTimeout(function(){
fn.ref(); //call function reference
},(idx==0)?idx:1000);
}
//fn - {ref:functionReference,order:true/false};
You could use deferred objects, but why don't you just use one timer and call the functions one by one?
var funcs = [/* array of functions */];
function next() {
var func = funcs.shift();
if(func) {
func();
setTimeout(next, 100);
}
}
next();
Things get more complicated if some functions can run "in parallel" and some are dependent, but you don't provide a lot of information about this.
But it wouldn't make much of a difference either. If you don't use webworkers, any JavaScript is run sequentially, even if you use setTimeout. Just the order of execution is not determined.
If I understand your question, each function you put in the list can have a flag that says, "Wait to execute me, until all previous functions have been executed". Therefore what you need to do is add a function count and code to each function you execute to decrement the count. Something like this, I put a copy in jsFiddle here:
var funcCount = 0, funcList = [];
function executeFunctions() {
var nextFunc;
while (funcList.length > 0) {
// Check next in list, if we need to wait, make sure we wait
nextFunc = funcList[0];
if (nextFunc.needToWait) {
if (funcCount > 0) {
// Try again later
setTimeout(executeFunctions, 100);
return;
}
}
// Since we are now going to execute, remove from list and execute
funcList.splice(0, 1);
funcCount += 1; // nextFunc will subtract 1 on completion
setTimeout(nextFunc, 100);
}
}
// For async functions to call back to completion
function completionCallback() {
funcCount -= 1;
}
To test it I have defined two functions. The first simulates async with a long timeout. The second has the wait flag set so it needs to wait for the first. Then I add them both to the list and test it:
// Example function 1 is simulated async
function example1() {
alert("Example1");
// Simulate async call with completion callback function, e.g. XHttpRequest
setTimeout(completionCallback, 2000);
}
example1.needToWait = false; // Not flagged
// Example function is flagged as need others to complete first
function example2() {
alert("Example2");
funcCount -= 1;
}
example2.needToWait = true;
// Setup function list to execute example1 then example2
funcList.push(example1);
funcList.push(example2);
// OK, test it
executeFunctions();
If you change the function2 flag to false, the alert boxes show up one after the other, right away. If you leave it as true, the second one doesn't show up until the 2 seconds have elapsed.