Is the function order guaranteed? - javascript

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.

Related

How event loop works in Javascript? [duplicate]

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.

Why is this async function is running synchronously?

I have some code here...
async function test() {
for(let i = 0; i < 10000; i++){
console.log("test");
}
}
console.log("a");
test();
console.log("b");
Now my understanding is that test() here should run asynchronously and if I would want to run a routine after it's completion I would use .then() after it.
I'm not doing that here though so surely it should just do it's thing in the background while everything else contiunes running? With that understanding I would expect some output like this:
a
b
test
test
..etc
However what I actually get is this...
a
test
test
...etc
b
Why does this happen? It seems that console.log("b") waits until test() completes but that's synchronous behaviour.
Apologies if something similar has been asked before but I couldn't find anything on this myself.
Setting something as async will wrap the return object into a Promise. Promises are used to deal with asynchronous behavior, but there's nothing inherently asynchronous about the content of the test function. If instead you were to wrap the contents into a setTimeout function, that would cause a delay which would mimic asynchronous behavior and match the outcome you were expecting.
async function test() {
setTimeout(() => {
for(let i = 0; i < 2; i++){
console.log("test");
}
})
}
console.log("a");
test();
console.log("b")
If you're looking to set up background tasks that can lock up the browser's main thread, you should check out WebWorkers. They are a way to offload performance impacting tasks onto a separate thread.
Synchronous code inside an async function runs synchronously. The interpreter will only move on to the next line after the call of the async function (here, the console.log("b");) after all synchronous code has finished - for example, if it runs into an await.
Here, since there's no await or anything asynchronous at all going on in test, test runs to the end before the next line (that logs b) runs.
It's pretty similar to how the Promise constructor runs.
From MDN:
An async function can contain an await expression, that pauses the execution of the async function and waits for the passed Promise's resolution, and then resumes the async function's execution and returns the resolved value.
If you do not have an await expression you are never 'pausing' the coroutine and it will execute synchronously without letting other functions run.
an async function means that what is inside the function is expected to have some asynchronous calls. like if you had an Http call inside your test function.
and since nothing is asynchronous inside your function (you only have a normal loop) then your function will execute normally and sequentially until it finishes executing.
async keyword don't mean that function wil run asynchronously. To run it asynchronously use setTimeout or Promise etc.
function test() {
setTimeout(() => {
for(let i = 0; i < 3; i++){
console.log("test");
}
});
}
console.log("a");
test();
console.log("b");
Async keyword usually is used with Promises and await keyword to write async code in synchronous way (to use await keyword we need put code inside async function)
function test() {
return new Promise( res => {
for(let i = 0; i < 3; i++){
console.log("test");
}
res();
});
}
async function start() {
console.log("a");
await test();
console.log("b");
}
start();

setTimeout(..0) ordering

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.

JavaScript execution flow

Is my assumption right?
Given the following code:
function test() {
for(let i=0 ; i < 100000; i++) {
// Do a set of costly operations that are NOT ASYNCHRONOUS
}
}
test();
myScriptElement.onload = test;
My assumption is "no", there is no chance for myscriptElement.onload to be executed (test function) before the first test call has terminated
… Since JavaScript has a single "thread" which keep on executing instructions until it reaches some asynchronous code, save current callstack/context/etc, put it into a job queue like area, then execute the next eligible item in that queue or wait for one to come in.
Is that right?
Or, should I make sure the first test function call has returned, like with the help of a boolean flag:
let terminated = false;
myscriptElement.onload = function specificHandler(e) {
if (terminated) {
test();
return;
}
setTimeout(specificHandler.bind(null, e), 1000);
};
Thank you.

Call Stack while using setTimeout()

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').

Categories

Resources