洋葱模型的核心思想

1,219 阅读2分钟

洋葱模型是一种中间件流程控制方式。顾命就是用来控制流程的,我这里就讲解的很简单,主要把实现的思路做一个简单的讲解。

什么是洋葱模型

先看一张图:

这张图在网上特别流行,基本搜索一下洋葱模型每篇文章都有这张图来做讲解。比较形象的解释了洋葱模型是在处理请求来和响应请求之间的问题。可以类比栈,先进后出。

express的洋葱模型

大家只要讲洋葱模型,就会联想到koa的中间件,很少有人谈及express的洋葱模型和中间件原理。那么我就来反其道而行之,讲讲express的洋葱模型。以下是栗子:

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

const A = function A(req,res,next) {
	console.log('A 开始')
	next()
	console.log('A 结束')
}
const B = function B(req,res,next) {
	console.log('B 开始')
	next()
	console.log('B 结束')
}
const C = function C(req,res,next) {
	console.log('C 开始')
	next()
	console.log('C 结束')
}

app.get('/',A,B,C)

A 开始
B 开始
C 开始
C 结束
B 结束
A 结束

以上代码可以直接复制,直接运行,运行结果就是A=>B=>C=B=>A的结构,正如洋葱模型的结构。以上代码其实等价于以下代码,你可以理解为3个函数的调用是嵌套的,A点用BB调用CC结束释放,B结束释放,A结束释放的这么的一个流程。

function A() {
	console.log('A 开始')
	function B() {
		console.log('B 开始')
		function C() {
			console.log('C 开始')
			console.log('C 结束')
		}
		C()
		console.log('B 结束')
	}
	B()
	console.log('A 结束')
}

如何实现

大概的一个思想和逻辑我们已经了解,那该怎么将一个顺序执行的变成内部调用的逻辑呢?

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

实现的逻辑非常简单,每次迭代都是将next传递给用户,用户手动调用next之后就会跳到下个函数的执行,以此来达到内部迭代的目的。

express内部实现

	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);
    }
  }

espressnext就是用来迭代中间件的,handle_request可以认为就用传进来的方法也就是A,B,C每次迭代都会把当前的next传给用户,用户手动调用的时候,就会再次触动这个next函数,利用了闭包保留了idxstack

到这里就结束了,希望对你有些帮助。