How javascript callstack, queue handles http request inside promise - javascript

I am understanding how the js engine handles promises then I got this great article https://medium.com/#jitubutwal144/javascript-how-is-callback-execution-strategy-for-promises-different-than-dom-events-callback-73c0e9e203b1.
This made me very much clear.
But If we make an HTTP request inside the promise then when js see that promise object which contains Http request it adds its callback in the microtask queue and js call stack starts executing promise. It saw HTTP request and send's it to browser to make it. Now the browser is completed with it and add's http callback to task queue which calls resolve, request. According to its js engine first picks micro task but it cannot do anything with a microtask because its resultant callback is in the task queue. I am confused about how the js engine will handle it.
Can anyone please help

Related

How does the browser know when a promise has resolved?

I've been learning about the event loop that browsers use and how it processes macrotasks and microtasks when they are added to their respective queues.
My question is how does the event loop know that a promise has resolved so that it can then run the microtask of the then/catch/finally code?
For example say the promise is an HTTP request. The http request is sent within some function and code execution can continue synchronously. Some time later the promise resolves and the associated then code runs.
Is the HTTP request done on some other browser thread, which when it gets the result it then adds to the microtask queue that the then code can now be executed?

Is there a delay between task completion and callback function execution?

I am learning Node.js and some javascript. I read up some stuff of thinks like queues and execution stacks.
I am trying to calculate time taken by a websocket request to complete. A very typical emit is of form:
microtime1 = getTimeNow;
socket.emit("message","data", function (error, data) {
// calculate time taken by using microtime module by getting updated time and calculating difference.
microtime2 = getTimeNow;
time = microtime2 - microtime1;
})
If I am sending multiple messages, can I rely on callback getting executed without delay or can there be a hold up in the queue and callback won't get executed.
In other words, would callback only get called once it's in stack or does it get executed while it's waiting to be picked up in the queue ?
Hope, I was able to explain my question.
In other words, would callback only get called once it's in stack or does it get executed while it's waiting to be picked up in the queue ?
The callback gets executed after the event, that it is waiting for, is resolved.
So the callback should work just fine, however there is a caveat. because node-js is single threaded, you could have another process that's blocked the main thread.
For example the simple view of execution may look like this. One event is processed, and then another one is processed after.
However, in reality it may look more like this
The single thread is meant for the main thread only, things like the IO operations are done on another dedicated thread that will notify main thread when it's done, and then the callback can be executed after
The problem occurs if your main thread becomes busy while waiting for the network action to complete
This is hard to predict though and depends on what the rest of the app is doing. If your app is not doing anything else, this likely won't be an issue. But, IMHO, a better way is to make hundreds or thousands of calls and allow get an average which will account for other possible causes for discrepancies in the delta.
Additional data from c-sharpcorner.com
The above diagram shows the
execution process of Node.js. Let's understand it step by step.
Step 1
Whenever a request comes to Node.js API, that incoming request is
added to the event queue. This is because Node.js can't handle
multiple requests simultaneously. The first time, the incoming request
is added to the event queue.
Step 2
Now, you can see in the diagram that one loop is there which always
checks if any event or request is available in event queue or not. If
any requests are there, then according to the "First Come, First
Served" property of queue, the requests will be served.
Step 3
This Node.js event loop is single threaded and performs non blocking
i/o tasks, so it sends requests to C++ internal thread pool where lots
of threads can be run. This C++ internal thread pool is the part of
event loop developed in Libuv. This can handle multiple requests. Now,
event loop checks again and again if any event is there in the Event
Queue. If there is any, then it serves to the thread pool if the
blocking process is there.
Step 4
Now, the internal thread pool handles a lot of requests, like database
request, file request, and many more.
Step 5
Whenever any thread completes that task, the callback function calls
and sends the response back to the event loop.
Step 6
Now, event loop sends back the response to the client whose request is
completed.

In javascript on a browser, how is the microtask and webapi queue different?

I never see a "microtask" queue referenced in online sources and I wondered if this is because the webapi queue is what the microtask is referring to?
Here's a YouTube video that was viewed 1.5. million times that explains the JS event loop, but the "microtask queue" isn't even referenced: https://www.youtube.com/watch?v=8aGhZQkoFbQ
ADDENDUM:
This is a great resource to learn about tasks and microtask queues: https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API/Microtask_guide/In_depth
This link doesn't answer my question, but it does touch on the topic and provides some helpful clarity.
Within the nodejs "event loop" are a number of different queues for things waiting to run. There's a queue for asynchronous I/O things like file operations. There's a separate step of the event loop for timers (not really a queue as timers are implemented within the event loop in a very specific way). There's a microtask queue for promises. As the event loop looks for the next thing to do, it has a specific order it looks for things and some things (such as resolved/rejected promises) have higher priority that other things waiting to run.
I never see a "microtask" queue referenced in online sources and I wondered if this is because the webapi queue is what the microtask is referring to?
In that specific video, "webapi" is used as a giant placeholder for all the things that browser adds to its Javascript environment that are not built into the Javascript language itself. This would include Ajax, DOM, etc... There are indeed multiple queues that are part of what the browser adds to the vanilla Javascript implementation.
The ECMAScript specification uses the terms Jobs and Job Queues. Microtask is often used in reference to promises and their implementation which you can see referenced here on MDN, but it's used to just try to explain how the specification or an implementation works - that term isn't actually in the specification.
In general, the term microtask is used to describe a subset of some larger task that is waiting to run. For example, if you had something like this (where $.get() is an ajax call:
$.get("http://www.google.com").then(result => {
console.log("got the page");
}).catch(err => {
console.log(err);
});
Then, the browser would run $.get() and, sometime later when it completes and the JS engine is free, a callback would get called that would resolve the promise that $.get() returns. Resolving that promise would allow the promise to schedule it's .then() handlers to run. They get scheduled by inserting them into the promise microtask queue. And, when the current bit of Javascript finishes and returns back to the event loop, the event loop will run the first thing in that microtask queue and it will run it before it runs most other things in other queues that are also serviced by the event loop.

Promises under the hood (call stack, Web API, task queue)

I read a lot of articles about promises. I know that promise executions are microtasks for task queue, async code executions are tasks for task queue. How does it happen in promises that after asynchronous code works synchronous code (i.e. after some fetch we can write synchronous code in .then block)?
I guess that all code inside promises use callstack (if sync code inside Promise body) or task queue (if async code inside Promise body). I saw a lot of examples with callstack, Web API and task queue with setTimeout code but how it works with promises I can only assume.
Can you show on my examples what happens with callstack, Web API and task queue, please?
First example:
const promiseWithAsyncBody = new Promise(resolve=>
setTimeout(()=> resolve('resolved'), 0));
promiseWithAsyncBody.then(msg=> console.log(msg));
I guess that promise body gets into task queue, then it gets into in callstack, when code come into setTimeout, setTimeout gets into WebAPI and immediately gets into task queue but at the same moment .then block gets into the task queue. After that triggers setTimeout and only after setTimeout triggering .then block.
Second example:
const promiseWithSyncBody = new Promise(resolve=> resolve('resolved'));
promiseWithAsyncBody.then(msg=> console.log(msg));
I guess that promise body executes in callstack and till that executes .then block gets into the task queue. When callstack is empty, .then block executes.
Am I right? Explain in more details who knows please. Thank you!
When you create a promise
const promise = new Promise(/*executorFunction*/ (resolve, reject) =>
{/* executor function body */}
)
the body of executorFuncton is being executed right away.
Inside the body of executor function you may or may not call some asynchronous api's.
After a promise is just created it is in "pending" state.
If inside of executor function resolve callback is called, the promise's state becomes "fulfilled" (or it may became "rejected" if reject callback is called).
And only after the promise become fulfilled a microtask is crated (which wraps a callback you've provided in then() call) and pushed into microtask queue by browser.
The observable difference between task queue and microtask is that tasks in microtask queue always
run before tasks in task queue. And that's the only clear info about microtask and task queue I found on the internet when I was interested in this topic too.

Is javascript itself synchronous and it's the environment that is asynchronous?

Native javascript is single threaded and synchronous. Only a few objects can run asynchronously and get added to the callback queue such as HTTP requests, timers and events. These asynchronous objects are a result of the actual javascript environment and not javascript itself. setTimeout() seems to be the go to for examples for asynchronous code. That function gets moved to the web API container and then eventually the callback queue. There doesn't seem to be a way to write asynchronous code in javascript that doesn't involve using objects that get moved to the Web API container. I can write my own custom objects with callbacks, but the most that will do is structure it to run in the proper order. You can never write javascript code that runs in parallel that doesn't rely on those objects.
This is my understanding of how it works, if I am wrong please correct me.
setTimeout and setInterval are just a convenient way to trigger some asynchronous behavior for an example. It is part of standard javascript library in all implementations, and not just part of the browser environment.
But all other sources of async code depend on some external process. When making an HTTP request, your javascript thread tells the browser to make a request (what headers, what url, etc). The browser, according to its own compiled internals, then formats the request, sends it, waits for a response, and eventually adds an item to javascript's event loop to be processed next time the event loop runs. File system access and database queries are two other common examples of async code that depends on external processes (the OS, and a database, respectively)
How javascript handles async code in a single threaded process is all down to this event loop. This event loop in psuedo code is basically this:
while (queue.waitForMessage()) {
queue.processNextMessage();
}
setTimeout tells the environment to pop something into that queue at some point of the future. But the processing of that queue is single threaded. Only one event message can be handled at the same time, but any number can be added to that queue.
You can get true concurrency with workers, but this basically adds a new javascript process that is itself single threaded, and has a method of communicating with messages to and from the main javascript process.

Categories