See JavaScript references in Node. js, and node. jsjavascript
Early Learning Node. in js (2011-2012), many of them were transferred from PHP. At that time, some people were interested in Node. it is troublesome to restart the code after js editing (PHP does not need this process), so friends in the community began to advocate using the node-supervisor module to start the project, you can automatically restart after editing the code. However, it is not convenient enough for PHP, because after Node. js is restarted, the previous context is lost.
Although session data can be stored in the database or cache to reduce data loss during the restart process, in the case of production, the restart interval of the updated code cannot process the request (PHP can, and Node. js does not have a cluster ). Due to this problem, I switched from PHP to Node. since then, I began to think about whether there is a way to hot update the Node without restarting. js Code.
At first, I looked at the require module. The idea is simple, because a module introduced in Node. js is loaded using the require method. So I began to think about whether require could be used again after updating the Code. Try the following:
A. js
var express = require('express');var b = require('./b.js'); var app = express();app.get('/', function (req, res) { b = require('./b.js'); res.send(b.num); });app.listen(3000);
B. js
exports.num = 1024;
After the two JS files are written, start from a. js and refresh the page to output 1024 in B. js, and then modify the exported value in the B. js file, for example, to 2048. Refresh the page again and it will still be the original 1024.
Executing require again does not refresh the code. After the code is loaded during the execution of require, the data exported by the module is placed in require. cache. Require. cache is a {} object. The absolute path of the module is the key, and the detailed data of this module is value. Then we started to try the following:
A. js
Var path = require ('path'); var express = require ('express '); var B = require ('. /B. js '); var app = express (); app. get ('/', function (req, res) {if (true) {// check whether the file is modified flush ();} res. send (B. num) ;}); function flush () {delete require. cache [path. join (_ dirname ,'. /B. js ')]; B = require ('. /B. js ');} app. listen (0, 3000 );
Before re-require, clear the cache for the module above require and test again with the previous method. The result shows that the code of B. js can be refreshed successfully and the new value can be output.
After learning about this, I want to use this principle to implement a node-supervisor without restarting the hot update version. In the process of encapsulating a module, for the sake of feelings, consider providing a function similar to include in PHP to replace require to introduce a module. Actually, it is still loaded using require internally. Taking B. js as an example, the original statement is changedvar b = include(‘./b')
After file B. js is updated, include can automatically refresh internally to get the latest code from outside.
However, in the actual development process, the problem was quickly encountered. The code we want may be like this:
Web. js
var include = require('./include');var express = require('express');var b = include('./b.js');var app = express(); app.get('/', function (req, res) { res.send(b.num); });app.listen(3000);
But we found the problem when we encapsulated the include according to this goal. No matter how we implement it in include. js, we cannot get the new B. num as we did at the beginning.
Compared with the initial code, we found that the problem was less than B = xx. That is to say, you can write it like this:
Web. js
var include = require('./include');var express = require('express');var app = express(); app.get('/', function (req, res) { var b = include('./b.js'); res.send(b.num); });app.listen(3000);
This ensures that the latest code can be correctly refreshed each time without restarting the instance. If you are interested, you can study how this include is implemented. This article will not discuss it in depth, because this technique is not very easy to use and is not very elegant to write. [1], on the contrary, there is a more important issue-JavaScript reference.
Differences between JavaScript reference and traditional reference
To discuss this problem, we must first understand the difference between JavaScript reference and other languages. In C ++, you can directly modify external values by referencing:
# Include using namespace std; void test (int & p) // pass reference {p = 2048 ;}int main () {int a = 1024; int & p =; // set reference p to a test (p); // call the function cout <"p:" <p <endl; // 2048 cout <": "<a <endl; // 2048 return 0 ;}
In JavaScript:
Var obj = {name: 'Alan '}; function test1 (obj) {obj = {hello: 'World'}; // try to modify external obj} test1 (obj ); console. log (obj); // {name: 'Alan '} // function test2 (obj) {obj. name = 'World'; // modify the attributes on the object} test2 (obj); console. log (obj); // {name: 'World'} // modification successful ②
We found that, unlike C ++, the above Code ① shows that JavaScript does not pass a reference, but copies a new variable, that is, passing the value. According to ② we can see that the copied variable is a "reference" that can access the object property (different from the traditional C ++ reference, the JavaScript references mentioned below are special references ). Here we need to sum up a detour conclusion: values are transmitted in Javascript, and an object copies a new reference during the transfer process.
To understand this conclusion, let's look at a piece of code:
Var obj = {name: 'Alan '}; function test1 (obj) {obj = {hello: 'World'}; // try to modify external obj} test1 (obj ); console. log (obj); // {name: 'Alan '} // function test2 (obj) {obj. name = 'World'; // modify the attributes on the object} test2 (obj); console. log (obj); // {name: 'World'} // modification successful ②
Through this example, we can see that although data points to obj. data like a reference, and can access the properties on obj. data through data. However, the direct modification of data = xxx due to the passing of JavaScript values does not make obj. data = xxx.
For example, when var data = obj. data is initially set, the memory is probably:
| Addr | content | ---------- | -------- | obj. data | Memory 1 |
| Data | Memory 1 |
So we can modify the memory 1 of obj. data through data. xx.
Then set data = xxx. Since data is a new value copied, this value is a reference (pointing to memory 1. Making it equal to another object is like:
| Addr | content | ---------- | -------- | obj. data | Memory 1 |
| Data | memory 2 |
Point data to a new memory of 2.
If it is a traditional reference (C ++ reference mentioned above), then obj. data itself becomes the new memory 2, but in JavaScript, values are passed, and the object copies a new reference during the transfer process. Therefore, changing the new copy variable does not affect the original object.
Module. exports and exports in Node. js
In the preceding example, the relationship between obj. data and data is the relationship between module. exports and exports in Node. js. Let's take a look at the actual structure of the require file in Node. js:
Function require (...) {var module = {exports :{}}; (module, exports) =>{ // Node. in js, the file is actually wrapped with a layer of Self-executed functions. // The code inside your module is in the middle. function some_func () {}; exports = some_func; // so that exports no longer point to module. exports // and module. exports is still {} module. exports = some_func; // so that the settings can be modified to the original exports}) (module, module. exports); return module. exports ;}
So naturally:
Console. log (module. exports === exports); // true // Therefore, the operation of exports is module. exports.
The exports in Node. js is a copy of the module. exports reference. You can use exports to modify the attributes exported from the current Node. js file, but cannot modify the current module itself. You can use module. exports to modify it. Performance:
Exports = 1; // invalid module. exports = 1; // valid
This is the difference in performance between the two, and there is no difference in other aspects. So now you should know that the person who writes module. exports. xx = xxx; actually writes another module ..
More complex examples
To practice it again, let's look at a complicated example:
var a = {n: 1}; var b = a; a.x = a = {n: 2}; console.log(a.x);console.log(b.x);
According to the conclusion, we can look at this problem step by step:
Var a = {n: 1}; // reference a pointing to memory 1 {n: 1} var B = a; // reference B => a => {n: 1}
Internal Structure:
| Addr | content | --------- | ------------- |
| A | Memory 1 {n: 1} | B | Memory 1 |
Continue to look down:
A. x = a = {n: 2}; // (memory 1 instead of a). x = reference a = memory 2 {n: 2}
A is a reference, but JavaScript is a reference of value passing, so the modification does not affect the original place.
| Addr | content | ----------- | ----------------------- |
| 1) a | memory 2 ({n: 2}) | 2) memory 1.x | memory 2 ({n: 2}) |
| 3) B | Memory 1 ({n: 1, x: memory 2}) |
So the final result
A. x (memory 2). x ==>{ n: 2}. x ==> undefined
B. x (memory 1). x ==> memory 2 ==>{ n: 2}
Summary
There is no reference transfer in JavaScrip t and only value transfer. The transfer of an object (reference type) only copies a new reference. This new reference can access the attributes of the original object, however, the new reference itself is a value placed on another grid. assigning a new value directly to this grid does not affect the original object. Node. this problem occurs when js is updated. The difference is that the object itself has changed, and the originally copied reference still points to the old memory, so no new method can be called through the old reference.
Node. js does not apply black magic to JavaScript, and the reference problem is still the content of JavaScript. For example, module. exports and exports hide some details, which are easy to misunderstand. The essence is still JavaScript.
Note [1]:
To be honest, the module declaration in the function is a bit of Tan haoqiang's feeling.
Write B = include (xxx) in the call. You can also set it as a middleware and bind it to a public place.
In addition to writing the code inside the call, you can also export a factory function. each time you use B (). num, you can call it once.
It can also be bound to the public objects of the framework in the form of middleware (for example, ctx. B = include (xxx )).
To implement such a hot update, you must strictly avoid the possibility of the old Code being referenced in the architecture; otherwise, it is easy to write code with Memory leakage.
The above is the reference of JavaScript in Node. js introduced by xiaobian. I hope it will be helpful to you. If you have any questions, please leave a message and I will reply to you in a timely manner. Thank you very much for your support for the help House website!