How to check pending schedules in queue schedular of RxJS? - javascript

I am using this code in for loop: my purpose was to once I get response of 1st request then only it should execute second request then 3rd and so on.
queueScheduler.schedule(() => {
this.ajaxcall().subscribe((res) => {
console.log('blah blah blah', res);
});
});
Now if my loop has 10 request, it means that while 2request is in progress. then 8 requests are in queue. how can I know how many requests are in queue?
How to check that pending requests?

You are scheduling creation of ajaxcall's, but creating and subscribing to the observable is synchronous (the subscription callback will be called asynchronously, but you don't refer to the queueScheduler there).
Therefore, queueScheduler runs the scheduled task synchronously and queueScheduler.actions is the empty queue.
The queueScheduler only queues up tasks if you call queueScheduler inside of a task run by the queueScheduler.

Related

JavaScript async callbacks - Promise and setTimeout [duplicate]

This question already has answers here:
Promise vs setTimeout
(6 answers)
What is the relationship between event loop and Promise [duplicate]
(2 answers)
Closed 1 year ago.
In the following code:
setTimeout(() => console.log("hello"), 0);
Promise.resolve('Success!')
.then(console.log)
What should happen in my understanding:
setTimeout is called => print hello directly added to callback queue as time is 0
Promise.resolve => print Success! added to callback queue
If I am not wrong, the callback queue is FIFO.
But the code output is:
Success!
hello
What is the explanation?
There are 2 separate queues for handling of the callbacks. A macro and a micro queue. setTimeout enqueues an item in the macro queue, while promise resolution - to the micro queue. The currently executing macro task(the main script itself in this case) is executed synchronously, line by line until it is finished. The moment it is finished, the loop executes everything queued in the microtask queue before continuing with the next item from the macro queue(which in your case is the console.log("hello") queued from the setTimeout).
Basically, the flow looks like this:
Script starts executing.
MacrotaskQueue: [], MicrotaskQueue: [].
setTimeout(() => console.log("hello"), 0); is encountered which leads to pushing a new item in the macrotask queue.
MacrotaskQueue: [console.log("hello")], MicrotaskQueue: [].
Promise.resolve('Success!').then(console.log) is read. Promise resolves to Success! immediately and console.log callback gets enqueued to the microtask queue.
MacrotaskQueue: [console.log("hello")], MicrotaskQueue: [console.log('Success!')].
The script finishes executing so it checks if there is something in the microtask queue before proceeding with the next task from the macro queue.
console.log('Success!') is pulled from the microtask queue and executed.
MacrotaskQueue: [console.log("hello")], MicrotaskQueue: [].
Script checks again if there is something else in the microtask queue. There is none, so it fetches the first available task from the macrotask queue and executes it, namely - console.log("hello").
MacrotaskQueue: [], MicrotaskQueue: [].
After the script finishes executing the console.log("hello"), it once again checks if there is anything in the microtask queue. It is empty, so it checks the macrotask queue. It is empty as well so everything queued is executed and the script finishes.
This is a simplified explanation, though, as it can get trickier. The microtask queue normally handles mainly promise callbacks, but you can enqueue code on it yourself. The newly added items in the microtask queue will still be executed before the next macrotask item. Also, microtasks can enqueue other microtasks, which can lead to an endless loop of processing microtasks.
Some useful reference resources:
The event loop
Microtasks
Using Microtasks
There are two different queues involved here: a Task queue and a Microtask queue.
Callback functions scheduled using setTimeout are added in the task queue whereas the callbacks scheduled using promises are added in the microtask queue or a job queue.
A microtask queue is processed:
after each callback as long as the call-stack is empty.
after each task.
Also note that if a microtask in a microtask queue queues another microtask, that will also be processed before processing anything in the task queue. In other words, microtask queue will be processed until its empty before processing the next task in the task queue.
The following code snippet shows an example:
setTimeout(() => console.log('hello'), 0);
Promise.resolve('first microtask')
.then(res => {
console.log(res);
return 'second microtask';
})
.then(console.log);
In your code, callback function of setTimeout is added to the task queue and the Promise.resolve queues a micro-task in a microtask queue. This queue is processed at the end of the script execution. That is why "success" is logged before "hello".
The following image shows a step-by-step execution of your code:
Resources for further reading:
Tasks, microtasks, queues and schedules
JavaScript job queue and microtasks
Even though the timeout is 0, the callback function will still be added to the web API (after being fetched from the call stack). Web APIs are threads that you can’t access; you can just make calls like Ajax, Timeout, and the DOM.
Promise.resolve schedules a microtask whereas setTimeout schedules a macrotask. Microtasks are executed before running the next macrotask.
So in your example, the
Promise.resolve('Success!').then(console.log);
will be executed before the setTimout since promises have better priority than the setTimeout callback function in the event loop stack.

How does the JS event loop behave when a Promise's resolution depends on setTimeout?

console.log('1')
setTimeout(() => {
console.log('2')
}, 0)
function three() {
return new Promise(resolve => {
setTimeout(() => {
return new Promise(resolve => resolve('3'))
},0)
})
}
three().then(result => console.log(result))
console.log('4')
This code snippet outputs 1 4 2
This is the behavior I would expect based on my understanding of javascript's event loop and concurrency model. But it leaves me with some lingering questions.
Before getting to those questions, I'll first break down my understanding of this code snippet.
Why code outputs 1
no explanation needed
Why code outputs 4
the callback that outputs 2 gets loaded into the event queue (aka macro task queue) after 0ms, but doesn't get executed until the main call stack is emptied.
even if three was a promise that was immediately resolved, its code is loaded into the job queue (aka microtask queue) and wouldn't be executed until the main call stack is emptied (regardless of the contents of the event queue)
Why code outputs 2
after console.log(4) the main call stack is empty and javascript looks for the next callback to load on the main stack. It's pretty safe to assume that at this point, some "worker thread" had already put the callback function that outputs 2 onto the macro task queue. This gets loaded onto the stack and 2 is output.
Why code does NOT output 3
This is where its a little blurry for me. The function three returns a promise that is then-ed in the main thread. Callback functions passed through then are loaded onto microtask queue and executed before the next task in the macrotask queue. So while you might think it'll run before the callback that logs 2, its actually theoretically impossible for it to run at all. That's because the Promise is only resolved via the callback function of its setTimeout, and that callback function (because of setTimeout) would only run if the main execution thread (the same thread that's waiting for the promise to resolve) is empty.
Why does this bother me
I'm trying to build a complete theoretical mental model of how javascript handles concurrency. One of the missing pieces in that model is the relationship between network requests, promises, and the event loop. Take the above code snippet, and suppose I replace three's setTimeout with some sort of network request (a very common thing in async web development). Assuming that the network request behaves similarly to setTimeout, in that when the "worker thread" is done, a callback is pushed to the macro task queue, it's hard for me to understand how that callback even gets executed. But this is something that happens literally all the time.
Can someone help me understand? Do I have any missing gaps in my current understanding of js concurrency? Have I made an incorrect assumption? Does any of this actually make any sense? lol
Why code does NOT output 3
In this code:
function three() {
return new Promise(resolve => {
setTimeout(() => {
return new Promise(resolve => resolve('3'))
},0)
})
}
three().then(result => console.log(result))
You never resolve the first Promise that three() creates. Since that's the one that is returned form three(), then the .then() handler in three().then(...) is never called.
You do resolve the promise created inside the timer, but you're returning that promise only to the timer callback which does nothing.
If you change your code to this:
function three() {
return new Promise(resolve => {
setTimeout(() => {
resolve('3');
},0)
})
}
three().then(result => console.log(result))
Then, you would see the 3get output.
So, this doesn't have anything to do with the event loop or how it works. It has to do with not resolving the promise that three() returns so the .then() handler on that promise never gets called.
I'm trying to build a complete theoretical mental model of how javascript handles concurrency. One of the missing pieces in that model is the relationship between network requests, promises, and the event loop. Take the above code snippet, and suppose I replace three's setTimeout with some sort of network request (a very common thing in async web development). Assuming that the network request behaves similarly to setTimeout, in that when the "worker thread" is done, a callback is pushed to the macro task queue, it's hard for me to understand how that callback even gets executed. But this is something that happens literally all the time.
Network requests and promises and timers all go through the event loop. There are very complicated rules about how multiple events in queue at the same time are prioritized relative to one another. .then() handlers are generally prioritized first.
Think of the Javascript interpreter as this simplistic sequence.
Get event from event queue
If nothing in the event queue, sleep until something is in the event queue
Run callback function associated with the event you pull from the event queue
Run that callback function until it returns
Note, it may not be completely done with its work because it may
have started other asynchronous operations and set up its own
callbacks or promises for those. But, it has returned from the
original callback that started it
When that callback returns, go back to the first step above and get the next event
Remember that network requests, promises, timers and literally ALL asynchronous operations in node.js go through the event queue in this manner.
Why you assume that network request would behave as setTimeout?
It is a Promise which resolved() would go in microtasks

setTimeout performing before a task in micro task queue (Job queue)

I'm having trouble understanding why my code below logs the following in order:
"end"
"timeout done"
"promise"
I assumed that "promise" would log before "timeout done" since it has a priority over callback queue task (setTimeout).
My assumption after this observation is that until .then is called, the promise does not enqueue its task since it's not ready yet, and thus allows setTimeout to perform in the callback queue to be performed first. Is this correct?
const sampleFunction = function(e) {
setTimeout(() => console.log('timeout done'), 0)
const data = fetch(`https://jsonplaceholder.typicode.com/comments/1`)
.then(response => {
return response.json();
})
.then(json => {
/*doSomething*/
console.log('promise')
});
console.log('end')
}
Your console.log('promise') has to wait until your fetch().then() is done which involves a networking operation to another host (and thus non-zero time).
Your setTimeout() only has to wait until sampleFunction() returns and you get back to the event queue. So, since the fetch().then() is non-blocking and takes non-zero amount of time, when you first get back to the event queue, only the setTimeout() is ready to go. The networking operation will still be in process in the background.
So, this isn't a matter of prioritization. It's a matter of completion order. The setTimeout() inserts its completion event into the event queue long before the fetch() promise is resolved.
Perhaps you didn't realize that fetch() is non-blocking and calling it just initiates the operation and then your code execution continues after that?
In the console, you should see:
end
timeout done
promise
As long as your fetch() doesn't have any errors.

How to observe multiple task queues in JS event loop [duplicate]

This question already has answers here:
Which types of queues are in event loop?
(3 answers)
Closed 2 years ago.
I'm reading an article that explains the event loop and execution timings. In it, it's mention that there can be multiple task queues that the event loop can choose to from to execute tasks. My main question is when does the browser decide to create a new queue? I've tried to observe this happening, but so far haven't been able to.
Contrasted with this other article on the subject, there's no mention of multiple queues, so I'm either misunderstanding something or one of the two articles is incorrect somewhere.
I believe the two articles in question are just using different terminology.
In article 1:
An event loop has multiple task sources which guarantees execution order within that source...
In article 2
the event loop can have multiple task queues... tasks must be processed in insertion order in every queue.
To answer my own question about observing different queues, I think it's as simple as this:
function foo() {
console.log('Start of queue');
bar();
Promise.resolve().then(function() {
console.log('Promise resolved');
});
console.log('End of queue');
}
function bar() {
setTimeout(function() {
console.log('Start of next queue');
console.log('End of next queue');
}, 0);
}
foo();
//-> Start of queue
//-> End of queue
//-> Promise resolved
//-> Start of next queue
//-> End of next queue
The first task queue (or task source) is foo(). foo() calls bar(), and bar() calls a setTimeout() which sets up a new task queue (or task source). The way we can observe each task queue is to resolve a Promise. The Promise callback is inserted into the micro queue. All micro queue tasks are executed at the end of every task queue (or task source). Because we see Promise resolved between the End of queue and Start of next queue console logs, we can conclude that that we're observing different event queues.
https://www.youtube.com/watch?v=u1kqx6AenYw&feature=youtu.be This will help you understand I think. Skip to the 7min mark.
There can be multiple queues in the task queue, and then also micro task queue.
In HTML terms, the event loop for a page or set of pages from the same domain can have multiple task queues. Tasks from the same task source always go into the same queue, with the browser choosing which task queue to use next.

NodeJS Event Loop Multiple Request

I have a question on the following code below (Source: https://blog.risingstack.com/node-js-at-scale-understanding-node-js-event-loop/):
'use strict'
const express = require('express')
const superagent = require('superagent')
const app = express()
app.get('/', sendWeatherOfRandomCity)
function sendWeatherOfRandomCity (request, response) {
getWeatherOfRandomCity(request, response)
sayHi()
}
const CITIES = [
'london',
'newyork',
'paris',
'budapest',
'warsaw',
'rome',
'madrid',
'moscow',
'beijing',
'capetown',
]
function getWeatherOfRandomCity (request, response) {
const city = CITIES[Math.floor(Math.random() * CITIES.length)]
superagent.get(`wttr.in/${city}`)
.end((err, res) => {
if (err) {
console.log('O snap')
return response.status(500).send('There was an error getting the weather, try looking out the window')
}
const responseText = res.text
response.send(responseText)
console.log('Got the weather')
})
console.log('Fetching the weather, please be patient)
}
function sayHi () {
console.log('Hi')
}
app.listen(3000);
I have these questions:
When the superagent.get(wttr.in/${city}) in the getWeatherOfRandomCity method makes a web request to http://wttr.in/sf for example, that request will be placed on the task queue and not the main call stack correct?
If there are methods on the main call stack (i.e. the main call stack isn't empty), the end event attached to the superagent.get(wttr.in/${city}).end(...) (that will be pushed to the task queue) will not get called until the main call stack is empty correct? In other words, on every tick of the event loop, it will take one item from the task queue?
Let's say two requests to localhost:3000/ come in one after another. The first request will push the sendWeatherOfRandomCity on the stack, the getWeatherOfRandomCity on the stack, then the web request superagent.get(wttr.in/${city}).end(...) will be placed on the background queue, then console.log('Fetching the weather, please be patient'), then the sendWeatherOfRandomCity will pop off the stack, and finally sayHi() will be pushed on the stack and it will print "Hi" and pop off the stack and finally, the end event attached to superagent.get(wttr.in/${city}).end(...) will be called from the task queue since the main call stack will be empty. Now when the second request comes, it will push all of those same things as the first request onto the main call stack but will the end handler from the first request (still in the task queue) run first or the stuff pushed onto the main call stack by the second web request will run first?
when you make http request, libuv sees that you are attempting to make a network request. Neither libuv nor node has any code to handle all of these operations that are involved with a network request. Instead libuv delegates the request making to the underlying operating system.
It's actually the kernel which is the essential part of our operating system that does the real network request work. Libuv is used to issue the request and then it just waits on the operating system to emit a signal that some response has come back to the request. So because Libuv is delegating the work done to the operating system the operating system itself decides whether to make a new threat or not. Or just generally how to handle the entire process of making the request. Each different os has a different method to handle this: On linux it is epoll, in mac os it is called kqueue, and in windows it is called GetQueuedCompletionStatusEx.
there are 6 phases in event loop and one of them is i/o poll. And every phase has precedence over others. number 1 is always timers. When time is up,(or event is done) timer's callback will be called to event queue and timer function are gonna move to event queue as well. Then event loop will check if it call stack is available. Call stack is where functions go to execute. You can do one thing at a time and the call stack enforces that we can only have one function on the top of the call stack that is the thing we're doing.There's no way to execute two things at the same time in JAVASCRIPT RUNTIME.
if the call stack is empty means main() function is removed, event loop will push the timer function to call stack and your function will be executed. None of the Async callbacks are EVER going to run before the main function is done.
So when it is time for i/o poll phase which handles incoming data and connections, with the same path how timer function followed, your function with handles the fetching will be executed.

Categories