The Onion model is a middleware process control method. Gu orders is used to control the process, I explain here is very simple, mainly the realization of the idea to do a simple explanation.

What is the Onion model

Let’s start with a picture:

This is a very popular picture on the Internet, so if you do a basic search on the Onion model, you’ll find this picture in every article. The onion model visually explains the problem between processing requests and responding to requests. Can be analogous to the stack, in and out.

The Onion model of Express

When people talk about the Onion model, they think of koA’s middleware. Very few people talk about express’s Onion model and middleware principles. So I’m going to go the other way and talk about express’s Onion model. Here are chestnuts:

const express = require('express')
const app = express();

const A = function A(req,res,next) {
	console.log('A beginning')
	next()
	console.log(End of the 'A')}const B = function B(req,res,next) {
	console.log('B start')
	next()
	console.log(End of the 'B')}const C = function C(req,res,next) {
	console.log('C start')
	next()
	console.log(End of the 'C')
}

app.get('/',A,B,C) A start B start C start D endCopy the code

The above code can be copied and run directly, and the result is A=>B=>C=B=>A structure, just like the onion model structure. The above code is actually equivalent to the following code, you can understand that the three function calls are nested, A point with B, B call C, C end release, B end release, A end release such A process.

function A() {
	console.log('A beginning')
	function B() {
		console.log('B start')
		function C() {
			console.log('C start')
			console.log(End of the 'C')
		}
		C()
		console.log(End of the 'B')
	}
	B()
	console.log(End of the 'A')}Copy the code

How to implement

We already know the general idea and logic, so how do you turn a sequential execution into internal call logic?

let index = -1
const FnArr = [A,B,C]
function next() {index++ FnArr [index] (next)if(index >= FnArr.length) { 
		return 
	}
}
next()
Copy the code

The implementation logic is very simple, each iteration is to pass next to the user, the user will manually call next after the execution of the next function, in order to achieve the purpose of internal iteration.

Express internal implementation

	next();

  function next(err) {
    // signal to exit route
    if (err && err === 'route') {
      return done();
    }

    // signal to exit router
    if (err && err === 'router') {
      return done(err)
    }

    var layer = stack[idx++];
    if(! layer) {return done(err);
    }

    if(layer.method && layer.method ! == method) {return next(err);
    }

    if (err) {
      layer.handle_error(err, req, res, next);
    } else{ layer.handle_request(req, res, next); }}Copy the code

In ESpress, next is used to iterate middleware. Handle_request can be considered as using the method passed in, that is, A, B and C will pass the current Next function to the user each iteration. When the user calls it manually, the next function will be touched again, using closures to preserve IDX and stack.

This is the end, I hope to help you some.