1. Opening analysis
Hello everyone, today's article mainly focuses on a source code analysis series for "Connect" middleware and related auxiliary middleware. I think everyone has read the previous article.
This article introduces the usage method and purpose, and this article is also out of my own interest, so that readers can have a deeper understanding of it. If there is any incorrectness in the analysis stage, please give me some advice.
alright! Let's get to the point of the old rules. Let’s take a look at an example first, and use the introduction analysis in combination, as follows:
The code copy is as follows:
var connect = require("./lib/connect");
var app = connect.createServer();
app.use(connect.static(__dirname + "/public",{
maxAge: 0
})) ;
app.use(function(req,res,next){
res.end("Hello World !");
})
.listen(8888);
2. Line by line analysis:
(1), the first line, introduce the "connect" module, create an http|https server through connect, and provide all the functions of http server.
The "connect" middleware allows you to create "servers" in a variety of ways.
The code copy is as follows:
var server = connect.createServer(
connect.logger()
, connect.static(__dirname + '/public')
) ; // 1
var app = connect() ;
app.use(function (req,res) {
res.end("Hello, Nobita!/n");
}).listen(8888); // 2
So how it does that, look at the source code:
The code copy is as follows:
exports = module.exports = createServer;
exports.createServer = createServer;
Mount "createServer" on the global "exports", then expand a "createServer" attribute and mount it again, the purpose is to be compatible with the native writing form.
The purpose of creating different ways has been achieved. This is also an idea that everyone can learn from in their daily development.
(2), let’s look at the second line "connect.createServer". What did it do, look at the source code below:
The code copy is as follows:
var HTTPServer = require('./http').Server,
HTTPSServer = require('./https').Server;
function createServer() {
if ('object' == typeof arguments[0]) {
return new HTTPSServer(arguments[0], Array.prototype.slice.call(arguments, 1));
} else {
return new HTTPServer(Array.prototype.slice.call(arguments));
}
};
"HTTPSserver" and "HTTPServer" are basically the same, they are just the https method encapsulated by "HTTPSserver". When "createServer", a series of middleware can also be passed in, which is the same as the subsequent introduction, but can only be bound to the root directory.
(3), continue to look at the third line "app.use()", what did it do, look at the source code as follows:
The code copy is as follows:
var Server = exports.Server = function HTTPServer(middleware) {
this.stack = [];
middleware.forEach(function(fn){
this.use(fn);
}, this);
http.Server.call(this, this.handle);
};
/**
* Inherit from `http.Server.prototype`.
*/
Server.prototype.__proto__ = http.Server.prototype;
"connect" is the prototype inherited from "http server", which will replace the server's requestListener with the middleware you use.
Use "connect.use(route, handle)" to add middleware to each route. The "handle" of these middleware will be bound to "route" and saved in a "stack". Every time there is a "request" request,
Traversing this heap, find the "handle" corresponding to "route", and execute "handle". If "handle" finally calls "next()", it will continue to search and execute the next matching "handle".
By encapsulating "handle", it is easy to add more "middleware" to "connect".
(4), finally, look at "listen(8888)", what kind of work does it do?
It is very simple. By inheriting the underlying Server object, it gives the function of "listen" to listen for specific ports.
Server.prototype.__proto__ = http.Server.prototype
The following is the entire source code of "connect.js". In order to save space, all comments have been deleted, as shown in the figure below:
To add:
The code copy is as follows:
fs.readdirSync(__dirname + '/middleware').forEach(function(filename){
if (//.js$/.test(filename)) {
var name = filename.substr(0, filename.lastIndexOf('.'));
exports.middleware.__defineGetter__(name, function(){
return require('./middleware/' + name);
});
}
});
The "middleware" object "exports" and then loop to the "middleware" object is a method that directly loads the .js file module in the "middleware" folder.
Use: "exports.utils.merge(exports, exports.middleware)" to directly export the methods in middleware.
Three, let’s summarize:
(1) Understanding the design intention of the source code will help maximize the gains in the application.
(2) When looking at the source code, understand the process and then deduct grammatical details.
(3) Learn from the clever implementation ideas in the source code, but do not transition design, design for the sake of design.
(4) Continue to analyze relevant middleware tomorrow and continue to be updated. . . . . .