5.20 released an online Ide that runs node.js – WebContainers on top of a browser

1 Node. Js

What exactly is Node.js? When I started learning Node.js, I didn’t know much about the front end (and I still don’t). My impression of Node.js was that it was almost the same syntax as Javascript, and then there was writing the back end. Remember at that time also secretly happy, learned Javascript = what will be! All right, cut to the chase

Javascript used to run in the browser, Javascript is a high-level language, computers can not directly read, after all, the binary computer world is only 010101… At this time, the JavaScript engine in the browser acts as a translator, translating what the JavaScript wants to do to the computer hand in hand, and the compilation process is not detailed (I don’t know for the time being).

Node.js is based on Chrome’s V8 engine and can compile Javascript efficiently, so it can be said that Node.js is another Javascript runtime environment besides the browser.

I remember the simple automatic reply of wechat public account on the cloud function of Tencent Cloud, and I had a little experience on the modularization of front-end code at that time, thanks to Node.js!

At the beginning of 2 experience

The server.js file is as follows

// Import the HTTP module
var http = require("http");

// Create the service with the HTTP module
 //req obtain url information (request)
 // The browser returns a response.
http.createServer(function (req, res) {
  // Set the HTTP header to 200, the file type to HTML, and the character set to UTF8
  // The content-type field is used to define the Type of the web file and the encoding of the web page. It determines how the browser will read the file
  res.writeHead(200, {
    "Content-Type": "text/html; charset=UTF-8"
  });

  // Print the value to the page
  res.write('Stop it, Kobayashi.');

  // End the response
  res.end();

}).listen(3000); // Listen to port 3000
Copy the code

Run Node server.js on the terminal, open the browser, enter http://localhost:3000/ in the address bar, and you can see the page printed:

At this point, we set up a simple server locally, with the browser as the client to access

2.1 modular

In the code above, we notice that var HTTP = require(” HTTP “); To import the HTTP module. In Node, modules are divided into two types: one is the module provided by Node, called the core module; HTTP is one of the core modules, for example, the HTTP module can create services, the PATH module processes file paths, the URL module processes and parses URl.fs module is used to read and write system files and directories, etc.

2.1.1 CommonJS

When it comes to modularity, we must mention CommonJS. Node.js uses part of CommonJS syntax, which can be understood as a standard for modularity. In the early stage, in order to solve the problem of error-prone dependency order caused by the introduction of JS file code through script tag, variable pollution caused by top-level scope and so on

Here’s a quick look at the differences between module. Exports and exports

Test2. Js as follows:

let str = require('./test1');
console.log(str)
Copy the code

When test1.js is as follows:

let str1 = 'Stop it, Xiao Lin 1'
let str2 = 'Stop It, Xiao Lin 2'

exports.str1 = str1
exports.str2 = str2
console.log(module.exports === exports)
Copy the code

Run node test2.js on the terminal. The result is as follows:

/* output {str1: 'str1 ', str2: /* exports. Str1 = str1 module.exports = str2 console.log(module.exports === =) Exports) output: 5 */ /* export.str1 = str1 module.export.str2 = str2 console.log(module.exports === exports) True {str1: '1', str2:' 2'} */Copy the code

Can be summarized:

Exports: exports: module exports: module exports: module exports Module. Exports = str2, and str1 did not export.

Also note that using exports exports is exporting an object

2.1.2 Es Module

Javascript is also in constant progress, this is not the Es6 version of the Es Module

Export:

export const str1 = 'Stop it, Xiao Lin 1'
export const str2 = 'Stop It, Xiao Lin 2'
export default {
    fn(){},msg: "Stop it, Kobayashi."
}
Copy the code

Import:

import { st1,str2,obj } from './test.js'
Copy the code

Note that import, direct node JS file execution will report error, need to Babel compilation

For comparison:

CommonJs can load statements dynamically, with code occurring at run time

The Es Module is static. Statements cannot be loaded dynamically. Statements can only be declared at the top of the file, and the code happens at compile time

2.1.3 Third-party modules

In addition to the core modules and custom modules provided by Node, third-party modules can also be used

That brings us to NPM, Node’s package management tool, which has become the world’s largest open source ecosystem for downloading packages.

There is also Yarn, of course, but I’ve only used NPM for the time being as it comes with Node.

2.2 Node Event Loop

2.2.1 Non-blocking I/ OS

A server-side language, such as Java, PHP, or.NET, creates a new thread for each client connection. Instead of creating a new thread for each client connection, Node uses only one thread.

console.log('1')
setTimeout(() = > {
  console.log('2')})console.log('3')/ / output 132
Copy the code

Javascript code executes line by line from top to bottom, but here it doesn’t block, output 3, output 2

2.2.2 Event loop

It took me a long time to understand Node’s event loop. I’ve read a lot of blogs, and I think it’s easiest to understand Node’s event loop by analyzing it in the context of the code and its results.

The Libuv library is responsible for the execution of the Node API. It assigns different tasks to different threads, forming an Event Loop that asynchronously returns the execution results to the V8 engine. The event loop in the Libuv engine is divided into six stages, which run repeatedly in sequence. Whenever a phase is entered, the function is retrieved from the corresponding callback queue and executed. When the queue is empty or the number of callbacks executed reaches a threshold set by the system, the next stage is entered.

console.log('start')
setTimeout(() = > {// Timer 1
  console.log('timer1')
  setTimeout(function timeout () {// Timer 2
    console.log('timeout');
  },0);
  setImmediate(function immediate () {// Timer 3
    console.log('immediate');
  });
  Promise.resolve().then(function() {
    console.log('promise1')})},0)
setTimeout(() = > {// Timer 4
  console.log('timer2')
  Promise.resolve().then(function() {
    console.log('promise2')})},0)
Promise.resolve().then(function() {
  console.log('promise3')})console.log('end')
Copy the code

You can run it on Node

Timers: This phase executes the callback of timer (setTimeout, setInterval)

I/O Callbacks phase: Handles a few unexecuted I/O callbacks from the previous loop

Idle, prepare: Used only in node

Poll phase: Gets a new I/O event, where the node blocks when appropriate

Check phase: Perform a callback to setImmediate()

Close Callbacks phase: Executes the socket’s close event callback

To understand: The poll phase is the entry point of the event loop, and asynchronous events are entered from here. After the synchronization task is executed, execute a micro task first and output the Timers. SetTimeout is the next step. Execute timer1, output timer1, add timer2 and timer 3 to the queue, once execute a task in a phase, immediately execute the microtask queue, so output promise1, then execute timer 4, output timer2,promise2, combined with event recircuation, To the check phase, perform the callback of setImmediate(), output immediate, recycle, reach the timer phase, output timeout

2.2.3 Event Loop of browser

Browser and Node event loops are different

I’m going to use two graphs and a piece of code to explain the browser’s event loop,

console.log(1)
setTimeout(() = >{console.log(2)},1000)// Macro task 1
async function fn(){
    console.log(3)
    setTimeout(() = >{console.log(4)},20)// Macro task 2
    Reject () reject() reject() reject() reject() reject() reject() reject() reject() reject(
    return Promise.resolve()
}
async function run(){
    console.log(5)
    await fn()
    //console.log(6),
}
run()
// It takes about 150ms to execute
for(let i=0; i<90000000; i++){}setTimeout(() = >{// Macro task 3
    console.log(7)
    new Promise(resolve= >{
        console.log(8)
        resolve()
    }).then(() = >{console.log(9)})},0)
console.log(10)
// 1 5 3 10 4 7 8 9 2
Copy the code

The execution result is as follows (please ignore my tooltip) :

Here’s a bit of foreknowledge: JavaScript is single-threaded, and tasks can be either synchronous or asynchronous. Tasks like console.log(‘1’) are synchronous, timer setTimeout,promise callbacks are asynchronous, etc. Synchronous is easy to understand, just go from top to bottom line to line, asynchronous is a little bit more complicated, there are macro tasks and microtasks.

The event loop mechanism of the browser is: the synchronization task is executed first, and the task in the task queue is executed after the synchronization task is executed. Then, where does the task in the task queue come from? Asynchronous tasks are queued when they are ready, and you can understand that there is a queue structure in the queue that manages macro and micro tasks. After the synchronization task is completed, there are microtasks in the task queue, and then a macro task is executed. After the macro task is executed, there may be microtasks. In this case, the microtasks need to be executed again. You can think of synchronization tasks as macro tasks, so you can understand that each macro task has to be cleaned up.

The above code is explained as follows: SetTimeout belongs to macro task 1, ready to queue for 1000 milliseconds, then execute function run, output 5, because of await, we need to wait for fn to finish executing, Async is async with await keyword, fn output 3, setTimeout macro task 2, prepare time 20 ms, return Promise of success status, output 6,for loop 150ms, this is macro task 2, ready, We go to the task queue, we go down, we have a setTimeout macro task 3, we don’t need to queue it, we execute the last line of code, output 10, so all the synchronous tasks have been executed, and now we have asynchronous tasks, task queue is a queue data structure, it’s first in, first out, At this point, there are macro tasks 2 and 3 in the task queue, first execute macro task 2, output 4, then execute macro task 3, output 7, promise itself is synchronous, output 8, callback then the code inside is a microtask, after macro task 3 is executed, there is a microtask, clean up one side of the microtask. Output 9, the entire process after 1000 milliseconds, macro task 1 joins the task queue, output 2

Here directly look at a big brother’s blog may be easier to understand, write not so good, cry, the link in the following.

Write not good, ashamed, will study hard!!

Reference links:

Understand the relationship between exports and module.exports

What are CommonJs and Es Modules and how they differ

Personal understanding of macro/micro tasks