yaobinwen / Web-Dev-Birds-Eye

A Bird's-eye view of web development to help novice web developers to speed up learning.
MIT License
0 stars 0 forks source link

Study JavaScript concurrency model, event loop, asynchronicity, promises, `fetch` API, `async` and `await` #4

Open yaobinwen opened 2 years ago

yaobinwen commented 2 years ago

Description

yaobinwen commented 2 years ago

Notes & Key Takeaways

[1] How JavaScript works in the browser

The overview of the JavaScript engine and the platform:

JavaScript engine and the platform

The job queue (or the promise queue).

[2] The Node.js Event Loop, Timers, and process.nextTick()

The execution of the event loop consists of six phases:

   ┌───────────────────────────┐
┌─>│           timers          │
│  └─────────────┬─────────────┘
│  ┌─────────────┴─────────────┐
│  │     pending callbacks     │
│  └─────────────┬─────────────┘
│  ┌─────────────┴─────────────┐
│  │       idle, prepare       │
│  └─────────────┬─────────────┘      ┌───────────────┐
│  ┌─────────────┴─────────────┐      │   incoming:   │
│  │           poll            │<─────┤  connections, │
│  └─────────────┬─────────────┘      │   data, etc.  │
│  ┌─────────────┴─────────────┐      └───────────────┘
│  │           check           │
│  └─────────────┬─────────────┘
│  ┌─────────────┴─────────────┐
└──┤      close callbacks      │
   └───────────────────────────┘

Each phase is a FIFO queue of callbacks to execute.

There are two factors that determine how long the event loop stays in one phase: whether the queue of that phase is exhausted or whether the maximum number of callbacks has reached.

... when the event loop enters a given phase, it will perform any operations specific to that phase, then execute callbacks in that phase's queue until the queue has been exhausted or the maximum number of callbacks has executed. When the queue has been exhausted or the callback limit is reached, the event loop will move to the next phase, and so on.

[3.1] The Node.js Event Loop

In general, in most browsers there is an event loop for every browser tab, to make every process isolated and avoid a web page with infinite loops or heavy processing to block your entire browser.

Any JavaScript code that takes too long to return back control to the event loop will block the execution of any JavaScript code in the page, even block the UI thread, and the user cannot click around, scroll the page, and so on.

Almost all the I/O primitives in JavaScript are non-blocking. Network requests, filesystem operations, and so on. Being blocking is the exception, and this is why JavaScript is based so much on callbacks, and more recently on promises and async/await.

It's the event loop that checks if there is anything in call stack to run:

The event loop continuously checks the call stack to see if there's any function that needs to run.

The event loop on every iteration looks if there's something in the call stack, and executes it until the call stack is empty.

Event loop on every iteration checks call stack

The message queue (roughly speaking, the "message queue" here is the "callback queue" above, while the "job queue" is different from the "message/callback queue"):

The Message Queue is also where user-initiated events like click or keyboard events, or fetch responses are queued before your code has the opportunity to react to them. Or also DOM events like onload.

The loop gives priority to the call stack, and it first processes everything it finds in the call stack, and once there's nothing in there, it goes to pick up things in the message queue.

Job queue is used by Promises (and async/await since they are built on top of Promises), both of which are introduced by ES6/ES2015. "It's a way to execute the result of an async function as soon as possible, rather than being put at the end of the call stack. Promises that resolve before the current function ends will be executed right after the current function."

[3.2] Understanding process.nextTick()

What is a "tick"?

Every time the event loop takes a full trip, we call it a tick.

"When we pass a function to process.nextTick(), we instruct the engine to invoke this function at the end of the current operation, before the next event loop tick starts." Although it says "before the next tick starts", I tend to interpret it as "at the very beginning of the next tick" which is equivalent to "at the end of the current tick".

Use nextTick() when you want to make sure that in the next event loop iteration that code is already executed.

[3.5] JavaScript Asynchronous Programming and Callbacks

The browser provides a way to do it by providing a set of APIs that can handle this kind of functionality.

How to handle errors when using callbacks? "One very common strategy is to use what Node.js adopted: the first parameter in any callback function is the error object: error-first callbacks. If there is no error, the object is null. If there is an error, it contains some description of the error and other information."