0

sorry to ask something sounds a bit stupid. I've looked up a bunch of documents and asked some people but I am still a bit confused.

So my question is:

  • Let's say I have 3 jobs currently, two of them (A, B) are synchronized jobs, and one (C) is a time-consuming asynchronized I/O bound operation.

  • So at first, A and B are in the call stack and C is in the callback queue. After A and B are finished, C would be pushed onto the call stack and starts to execute. But while C is running, a new synchronized job D is entered

  • Now, what happens?

I understand that if C is CPU-bound, then the execution would be just A->B->C->and D. And what I found online or in the document is that once a job starts to execute, even if it is an I/O bound, it will still finish it up first. but if that is, then why is javascript still a non-blocking language?

And plus what I found in my experience is that in my express server, if I have a function that spends a very long time querying in the database, and another request just entered, it wouldn't block by the querying.

  • 1
    What do you mean by "synchronized job"? Is this just a misspelling of "synchronous"? But then it doesn't really make sense. – Bergi Mar 10 '23 at 02:56
  • 1
    Can you explain what the term "job" means to you? And how a job is "entered"? – Bergi Mar 10 '23 at 02:58
  • "*why is javascript still a non-blocking language?*" - where did you read that it is? – Bergi Mar 10 '23 at 03:03
  • Kind reminder, browsers aren't written in JS, and they do use multiple process. The IO bound task might end up calling a JS callback, but the task itself isn't handled by JS. – Kaiido Mar 10 '23 at 03:18

2 Answers2

1

But while C is running, a new synchronized job D is entered

If D is synchronous, the moment D is called, any other tasks that depend on something asynchronous (such as waiting for a network request to come back) will not be able to handle possible completions of their callbacks until D has run to the end and finished. So, you could think of D as a blocking function - just like all synchronous functions, once it's called, it will block anything else from running until it finishes and control flow is yielded back to the caller.

So

why is javascript still a non-blocking language?

isn't a very accurate way to put it - it's quite possible to write expensive blocking synchronous code that creates UI problems as a result.

For a more concrete example:

const doSomethingExpensive = () => {
  for (let i = 0; i < 1e12; i++) {
    // something here
  }
};
const c = () => {
  fetch('/endpoint')
    .then(res => res.text())
    .then((result) => {
      // do something with result
    });
  doSomethingExpensive();
};

Above, when c is called, a network request is initiated with the fetch. But then doSomethingExpensive is called, which is an expensive synchronous function. Due to the fact that doSomethingExpensive is synchronous, the line // do something with result will not be able to run even if the network request has actually completed in the meantime, until doSomethingExpensive has completely finished.

That said, synchronous functions that are actually expensive and consume a lot of CPU until they're finished like doSomethingExpensive above are pretty uncommon in most situations. In contrast, inexpensive asynchronous tasks are much more common to run into.

And plus what I found in my experience is that in my express server, if I have a function that spends a very long time querying in the database, and another request just entered, it wouldn't block by the querying.

That query is an example of something that's either inexpensive (just waiting for the external database to produce a response), or something whose implementation is outside of JavaScript whose operation doesn't stop other JavaScript from executing due to how a computing environment is multithreaded.

CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
0

once a job starts to execute, even if it is an I/O bound, it will still finish it up first

You have a slight misunderstanding of what non-blocking is. This description is true regardless if the architecture is blocking or non-blocking. What non-blocking actually means is that waiting for events use interrupts instead of a polling loop.

This is a strong indicator of your misunderstanding:

After A and B are finished, C would be pushed onto the call stack and starts to execute

This is 99.99% false. C will not be pushed onto the call stack after A and B are finished. This strongly implies that you misunderstand what waiting for I/O actually do.

Now, how the runtime actually process A, B and C depends on how you initially call them.

For example, assuming that there is a function Z that is asynchronous that is configured to execute C. If you did:

A();
B();
Z().then(C);

Then A will be executed first. After that B will be executed, after that Z will put C onto the event queue (it's called a queue but it is really just a list of event handlers).

When the event that Z waits for happens the runtime will call C. This is exactly like a regular function call (as if you called C()) but instead of being called by your code it is called by the code that processes the event.

On the other hand if you did:

Z().then(C);
A();
B();

Z will be executed first and it will add C to the event queue. After adding C to the event queue A is executed and then B.

When the event that Z waits for happens the runtime will call C. If by coincidence the event that Z waits for happens during the execution of A the runtime will not even notice and will complete executing A and B. At the end of the execution of A and B the runtime will check the event loop and will immediately find that it needs to call C.

So in this one unlikely case, then yes - C will be executed after A and B completes. But that is only a coincidence. The reason C is executed is not because A and B completes but because the event that it is waiting for has happened.

For more details on how all this works you may want to look at some of my old answers to other questions:

I know that callback function runs asynchronously, but why?

How does node.js schedule asynchronous and synchronous tasks?

slebetman
  • 109,858
  • 19
  • 140
  • 171