# the preface


Since I started to contact with Node, I cannot do without reading books and courses. Most books and online tutorials are more or less about the use of various tool libraries in some frameworks or ecology (ecology is the “pride” of Node). They tend to be quick-fix. I think Node is one of the best in terms of learning cost and development efficiency.

These approaches are all good in the end and are a quick way for beginners to get started: learn a language (Javascript, Typescript…). , through the use of frameworks (Express, Koa…) The process of building a working Web application isn’t that difficult or satisfying (at least not as much as Java).

To be sure, both frameworks and all kinds of code libraries are designed to solve problems quickly. Online, “10 minutes to implement a Web application”, “10 lessons to teach you to build your own blog with Node”… There are a lot of tutorials out there, and these are very good for beginners, because all they need to do is follow the tutorial and click on a command step by step to create a decent Demo. Maybe you just know how to call the API of the framework to start a Web Service like Express

const Express = require('express') const app = new Express() app.get('/', (req, res) => { res.send('Hello World! '); }); app.listen(3000, () => { console.log('Example app listening on port 3000! '); });Copy the code

Execute Node app.js and visit http://localhost:3000 in your browser to get a simple Demo.

During the entire learning process, you might just import the Express library and call its API, and many people might even mistake it for Node. There are also a lot of people who think, I just need to know how to use the framework, I don’t need to know how to implement it, these are things that framework writers need to know.

I think both of these are wrong. Yes, Node is very flexible and native (simple). It doesn’t provide a native Web Service solution, but rather a rich, complete and efficient operating environment on which people can expand and build their own solutions. If before using these frameworks, you don’t know the implementation of the principle of the framework and operation principle of the Node itself, then encountered in actual function development, the framework can’t or haven’t solve the problem, you will be stuck, unable to use the existing knowledge and theory to try to locate and solve the problem quickly.

# text


In this article, SOME of the things I’ve come across or searched for on a regular basis
NodeRelated questions, in the form of q&A, help yourself to summarize and share with readers (update continuously…) .

What is the relationship between Node and the V8 engine? Can Node work alone without V8?

Node.js is a JavaScript runtime environment based on the Chrome V8 engine. The V8 engine was first used in Google’s Chrome browser to interpret and implement Javascript code, which has done a lot of optimization. Node.js code is compiled and executed using the V8 engine.

JXcore is a branch of Node. You can use Mozilla SpiderMonkey to run Node applications on iOS devices.

There are several key reasons to use V8:

  • V8 is open source software under the BSD license
  • The V8 is very fast
  • V8 focuses on networking and is more mature in HTTP, DNS, TCP, and more

#Q2. When to use export and module.exports when to use Node modules?

Export is a reference to module.exports. When we use require to refer to a module, we refer to module.exports. Exports that is shorter to type), e.g. Export. A = {say: ‘Hello world! ‘ } => module.exports.a = { say: ‘Hello world! ‘}.

Both address and value must be considered for reference relations.

// Exports: {exports: {say: 'Hello world! ' } } const export = module.exports console.log(export) // { say: 'Hello world! '} export.name = 'Node' console.log(module.exports) // { say: 'Hello world! ', name: 'Node'} // Export and module.exports refer to the same memory address, so they both belong to the same memory address. Export = function () {console.log('new')} module.exports = function () {console.log('new')} // export will not export this properly Module. Exports = module. Exports = module. Exports = module. Exports = module. Const func = function () {console.log('success! ') } export.func = func module.exports.func = funcCopy the code

#Q3. What is an event loop? Is it part of V8?

First we need to understand that an event-driven refers to the continuous transaction management to make decisions in the process of a kind of strategy, that is to follow the current point in time, in the event of a contractual mobilize resources available, related tasks, to solve problems constantly, prevent the accumulation of transaction, rather than the Node of a unique function, it is an introduction of the concept. This is the basic concept behind node.js asynchronous programming with a single thread, and one of node.js’s tricks for achieving high concurrency:

When our asynchronous operation starts, such as setTimeout, Node dispatches the operation to another thread to handle the event, executes the following code without blocking in the main thread, and returns the result to the main thread after the event completes, saving the main thread time to wait in the same step. This time can be used to deal with more things, efficient use of time and resources. When Node is started, an Event Loop has been started to listen for and catch events, and the whole process is handled by Libuv.

#Q4. What is the call stack? Is it part of V8?

The call stack is the basic mechanism for Javascript code execution. When we call a function, we push the function arguments and return address onto the stack. This allows the runtime to know where to resume code execution after the function ends. In Node.js, the call stack is handled by V8, and I found an example online:

Concepts of the stack and queue is a data structure, the stack is a last in, first out (LIFO) linear table, while the queue is first in first out, after in the syntax parsing, we will push the main function, first of all, to the bottom of the stack, and file header of the first function foo () exists in the stack, in the process of execution, according to the principle of last in, first out step by step implementation: Foo () => bar() => main(), which throws an error stack whenever any function fails, and that’s the basic background for looking at stack information.

There is no doubt that V8 provides Node with the ability to execute code, and stack execution and invocation are also dependent on V8

#Q5. setImmediateprocess.nextTickWhat is the relationship?

Learning Node, this problem is to mention, the existence of history is very long -. Explain the queue model for the event loop phase in Node.

┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ ┌ ─ > │ timers │ │ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┬ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ │ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┴ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ │ │ pending Callbacks │ │ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┬ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ │ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┴ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ │ │ idle, Prepare │ │ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┬ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ │ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┴ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ │ incoming: │ │ │ poll │ < ─ ─ ─ ─ ─ ┤ connections, │ │ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┬ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ │ data, Etc. │ │ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┴ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ │ │ check │ │ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┬ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ │ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┴ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ └ ─ ─ ┤ close callbacks │ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘Copy the code

In short, setImmediate queues a function after any I/O event callbacks already in the event queue. Process.nexttick queues functions at the head of the event queue for execution as soon as the currently running function completes. The background to this problem is explained in the Official Node documentation:

In v0.8 (and before), the process.nextTick() function scheduled its callback using a spinner on the event loop. This usually caused the callback to be fired before any other I/O. However, it was not guaranteed.

As a result, a lot of programs (including some parts of Node’s internals) began using process. NextTick As a “do later, But before any actual I/O is performed “interface. Since it usually works that way, it seemed fine.

However, under load, it’s possible for a server to have a lot of I/O scheduled, to the point where the nextTick gets preempted for something else. This led to some odd errors and race conditions, which could not be fixed without changing the semantics of nextTick.

So, that’s what we did.in v0.10, nextTick handlers are run right after each call from C++ into JavaScript. That means that, if your JavaScript code calls process.nextTick, then the callback will fire as soon as the code runs to completion, but before going back to the event loop. The race is over, and all is good.

However, there are programs out in the wild that use recursive calls to process.nextTick to avoid pre-empting the I/O event loop for long-running jobs. In order to avoid breaking horribly right away, Node will now print a deprecation warning, and ask you to use setImmediate for these kinds of tasks instead.

Prior to Node V0.8, the process.Nexttick () function used a micro Task on the event loop to schedule its callbacks. This usually results in callbacks being triggered before any other I/O and is not guaranteed… So much I/O that nextTick preempts other content. This leads to some strange errors and race conditions that cannot be fixed without changing the semantics of nextTick. In V0.10 the nextTick handler runs immediately after each call from C ++ to JavaScript. This means that if JavaScript code calls process.nexttick, the callback will be triggered as soon as the code is finished running, before the event loop is returned.

#Q6. How to return a value in an asynchronous function instead of writing callback?

The problem is akin to “how to avoid callback hell.” In modern times, just make a Promise

return Promise.resolve('end')

new Promise((resolve, reject) => {
    resolve('end!')
})
Copy the code

What are the main differences between # q7. spawn, exec, and fork?

These attributes are the three ways in which child processes are created in Node by calling the child_process module to perform a series of operations

  • Child_process.spawn () : Child processes are spawned asynchronously and do not block the Node.js event loop.
  • Child_process.spawnsync () : provides the same functionality in a synchronous manner, but blocks the event loop until the spawned child process exits or is terminated.
  • Child_process.exec () : Spawn a shell and run commands on the shell, passed in when finishedstdoutstderrTo the callback function.
  • Child_process.fork () : Spawn a new Node.js process and invoke the specified module by setting up an IPC communication channel that allows parent and child processes to send messages to each other.

    Nodejs: How to play child_process

How does the q8.cluster module work?

The basics of the CLUser module still pass
child_process.fork()Function to copy the worker process

Because Node.js is single-threaded, it cannot take full advantage of the server’s multi-core processor. To solve this problem, we usually start multiple Node.js processes to handle the high load. Cluster solves this problem by creating multiple child processes and sharing ports.

Its working principle is to establish multiple sub-processes, by the main process to receive new requests or connections, and then through the way of circulation distributed to the sub-processes for processing, so as to achieve simple load balancing.

#Q9. How to check the memory used by node.js processes?

There should be more than one answer to this question. Here I will simply list two, which can be added later:

  • Outside the code, through the server’s own process memory viewing tools for detection and exploration

  • Within the code, use process.memoryUsage() to view occupied memory

    {RSS: 4935680, heapTotal: 1826816, heapUsed: 650472, external: 49879} //heapTotal and heapUsed refer to V8 memory usage. External refers to the memory usage of C ++ objects bound to V8 managed JavaScript objectsCopy the code

#Q10. What is libuv? How does Node.js use it?

This is a problem that could be explained at great length, but I’m just going to give you the background and my superficial understanding

Libuv is a high-performance, event-driven I/O library, and provides cross-platform (such as Windows, Linux) API, its core work is to provide “event-loop” and some other Event notification and callback functions, provides some tools such as timers, Non-blocking network requests and so on. Is the provider of many of Node.js’s complex capabilities, such as event looping

#Q11. How to do the last operation before the Node process exits? Can this operation be asynchronous?

This is a very common and easy to ignore problem. During Node running, it is inevitable to encounter program crash or process exit due to internal errors or external reasons. We usually need to listen for this signal and record it.

The entire “exit” event can be listened for by registering the process.on(‘exit’) method, which cannot be asynchronous.

function exitHandler(options, err) {
    console.log('clean');
}

process.on('exit', exitHandler.bind(null));
Copy the code

In addition, there are many other events that process.on listens for:

  • Process. On (‘ beforeExit)
  • Process. On (” disconnect “)
  • Process. On (” message “)
  • Process. On (‘ rejectionHandled)
  • Process. On (‘ uncaughtException)
  • Process. On (‘ unhandledRejection)
  • Process. On () ‘warning’
  • Signal Events

Among them, unhandledRejection and uncaughtException are often encountered in our daily development. For example, the ‘unhandledRejection’ event will be issued whenever a Promise is rejected. If a normal catch() does not hold the stack, an unhandledRejection error will be generated.

Does # q12.Node rely on v8 and Libuv?

Node API: nodejs.org/en/docs/met…

#Q13. Require a module process?

  1. checkmodule._cacaheWhether the module has been cached.
  2. If there is no cache, a new module instance is created and cached.
  3. Called based on the given module namemodule.load()Method, which is called when the load is donemodule.compile()Method to compile.
  4. If an error occurs during the load/compile process, an error is thrown and the faulty module is removed from the cache.
  5. Finally return the dependent module:module.exports

How is the loop dependency of the module in # q14.Node caused? How can it be avoided?

Many of you will encounter this problem in your development, and Node has a special explanation for this problem.

Suppose we have a situation like this:

a.js:

console.log('a starting');
exports.done = false;
const b = require('./b.js');
console.log('in a, b.done = %j', b.done);
exports.done = true;
console.log('a done');
Copy the code

b.js:

console.log('b starting');
exports.done = false;
const a = require('./a.js');
console.log('in b, a.done = %j', a.done);
exports.done = true;
console.log('b done');
Copy the code

main.js:

console.log('main starting');
const a = require('./a.js');
const b = require('./b.js');
console.log('in main, a.done = %j, b.done = %j', a.done, b.done);
Copy the code

When main.js loads A.js, A.js loads B.js in turn. At this point, B.js tries to load A.js. In order to prevent infinite loops, the incomplete copy of the exported object of A.js will be returned to the B.js module. Then B. Js finished loading and provided its exports object to the A. js module. Both modules are complete when main.js loads them. So it prints:

$ node main.js
main starting
a starting
b starting
in b, a.done = false
b done
in a, b.done = true
a done
in main, a.done = true, b.done = true
Copy the code

To solve the problem of circular dependencies, we can rely on modules at runtime:

Function () {require('./a.js')}Copy the code

#Q15. Following the question, which extended files can be automatically recognized and required?

Many students may check ruan Yifeng teacher’s article to learn the source code, speak very clear, but the content may already be too old (basic concept unchanged), the source code has a certain update, the latest address: loader.js, here I only list the fragment to find the source path:

Among them:

module._findPath = function () { if (! filename && rc === 1) { // Directory. // try it with each of the extensions at "index" if (exts === undefined) // Default supported extensions:.js,. Json,. Node exts = object.keys (module._extensions); filename = tryPackage(basePath, exts, isMain); if (! filename) { filename = tryExtensions(path.resolve(basePath, 'index'), exts, isMain); } } } // Native extension for .js Module._extensions['.js'] = function(module, filename) { var content = fs.readFileSync(filename, 'utf8'); module._compile(stripBOM(content), filename); }; // Native extension for .json Module._extensions['.json'] = function(module, filename) { var content = fs.readFileSync(filename, 'utf8'); try { module.exports = JSON.parse(stripBOM(content)); } catch (err) { err.message = filename + ': ' + err.message; throw err; }}; // Native extension for .node Module._extensions['.node'] = function(module, filename) { return process.dlopen(module, path.toNamespacedPath(filename)); }; if (experimentalModules) { if (asyncESM === undefined) lazyLoadESM(); Module._extensions['.mjs'] = function(module, filename) { throw new ERR_REQUIRE_ESM(filename); }; }Copy the code

As you can see, require loads. Js,. Json, and. Node files by default.

Why call end() when starting a service and processing a request, response request?

Http. ServerResponse is itself a writable stream, and after processing all operations, we need to tell it that it is done: Response.end (), which signals to the server that all response headers and body have been sent. To tell the server that the response is complete, we must call Response.end ().

Off-topic: In the normal development learning process, when using stream, for example, to pass a file in the way of stream, if the posture is not correct, we may encounter Error: Write after end, which means that it is not allowed to write data to response after end().

#Q17. How to output multi-layer nested objects?

const obj = {
  a: "a",
  b: {
    c: "c",
    d: {
      e: "e",
      f: {
        g: "g",
      }
    }
  }
};    

const util = require('util');
console.log(util.inspect(obj, {depth: 0})); // prints: '{ a: \'a\', b: [Object]}'
console.log(util.inspect(obj, {depth: null})); // prints: '{ a: \'a\', b: { c: \'c\', d: { e: \'e\', f: { g: \'g\' } } } }'
Copy the code

Why bring this up? Console. log(obj) will only output: {a: ‘a’, b: {c: ‘c’, d: {e: ‘e’, f: {a: ‘a’, b: {c: ‘c’, d: {e: ‘e’, f: [Object]}}} can not see the contents of the f, this is a very painful thing!

What is the use of the node-gyp module?

When installing GRPC or node-jieba, you need to compile some low-level files, such as c++ files, etc.

Node-gyp is a cross-platform command line tool written in Node.js for compiling native node.js plug-in modules. It bundles the GYP project used by the Chromium team and takes the pain out of dealing with the various differences in the build platform. It is a replacement for the Node-waf program, removed for node V0.8. If you have a native plugin for a node that still has wscript files, then you must add a binding.gyp file to support the latest version of the node.

#Q19. If there is only one line of code in a js file: console.log(arguments), what will the script output?

For those of you who have seen the q&A before, we already know that the last step is to execute module._compile, which is a compilation of modules, which returns the contents of module.exports. Let’s look at the source code:

// Run the file contents in the correct scope or sandbox. Expose // the correct helper variables (require, module, exports) to // the file. // Returns exception, if any. Module.prototype._compile = function(content, filename) { content = stripShebang(content); // create wrapper function var wrapper = Module.wrap(content); var compiledWrapper = vm.runInThisContext(wrapper, { filename: filename, lineOffset: 0, displayErrors: true }); var inspectorWrapper = null; if (process._breakFirstLine && process._eval == null) { if (! resolvedArgv) { // we enter the repl if we're not given a filename argument. if (process.argv[1]) { resolvedArgv = Module._resolveFilename(process.argv[1], null, false); } else { resolvedArgv = 'repl'; } } // Set breakpoint on module start if (filename === resolvedArgv) { delete process._breakFirstLine; inspectorWrapper = process.binding('inspector').callAndPauseOnStart; } } var dirname = path.dirname(filename); var require = makeRequireFunction(this); var depth = requireDepth; if (depth === 0) stat.cache = new Map(); var result; if (inspectorWrapper) { result = inspectorWrapper(compiledWrapper, this.exports, this.exports, require, this, filename, dirname); } else { result = compiledWrapper.call(this.exports, this.exports, require, this, filename, dirname); } if (depth === 0) stat.cache = null; return result; };Copy the code

You can see it clearly

result = compiledWrapper.call(this.exports, this.exports, require, this, filename, dirname); // {exports, require, module, __filename, __dirname}}Copy the code

#Q20. These are some of the things that can be done asynchronously. Callbacks and events are some of the things that can be done asynchronously.

These two functions perform an asynchronous operation, while an emitter can send its execution to another place. Callback can only be written to the current function or file.

// callback
(function () {
    setTimeout(() => {
    	console.log(1)
	})
})()

// Emitter
(function () {
	emitter.emit('print 1')
})()

emitter.on('print 1', () => {
    console.log(1)
})
Copy the code

The latter is more practical and flexible in the project structure.

# q21.console.time () is also a useful method. Where is it used?

Console.time () is usually not used alone, but in conjunction with console.timeend () to measure the elapsed time of an operation:

console.time('100-elements'); for (let i = 0; i < 100; i++) {} console.timeEnd('100-elements'); / / prints 100 - elements: 225.438 msCopy the code

Continuously updated…