H5W3
当前位置:H5W3 > 其他技术问题 > 正文

一篇文章了解洋葱圈模型——看了就忘不掉的那种

1. 洋葱圈模型

不管怎么聊,这张图还是要放一下的。可以看到,每个中间件都是一个洋葱圈。每次当有一个请求进入的时候,每个中间件都会被执行两次。例如下面的例子:
image.png

const Koa = require("koa")
const app = new Koa()
// 中间件A
app.use(async (ctx, next) => {
console.log("A1")
await next()
console.log("A2")
});
// 中间件B
app.use(async (ctx, next) => {
console.log("B1")
await next()
console.log("B2")
});
// 中间件C
app.use(async (ctx, next) => {
console.log("C1")
await next()
console.log("C2")
});
app.listen(3000);
// 输出
// A1 -> B1 -> C1 -> C2 -> B2 -> A2

2.核心理念

首先,我们来分析一下:

每个中间件都接收了一个next参数,在next函数运行之前的中间件代码会在一开始就执行,next函数之后的代码会在内部的中间件全部运行结束之后才执行。

要想达到上面洋葱圈的运行效果,我们需要做什么呢?

我们带着这样的一个思路,再回头来看Koa是如何实现的:

完美!下面只需要具体分析一下它们分别做了什么就可以了

// middleware用来保存中间件
app.use = (fn) => {
this.middleware.push(fn)
return this
}
// compose组合函数来规定执行次序
function compose (middleware) {
// context:上下文,next:传入的接下来要运行的函数
return function (context, next) {
function dispatch (i) {
index = i
// 中间件
let fn = middleware[i]
if (!fn) return Promise.resolve()
try {
// 我们这边假设和上文中的例子一样,有A、B、C三个中间件
// 通过dispatch(0)发起了第一个中间件A的执行
// A中间件执行之后,next作为dispatch(1)会被执行
// 从而发起了下一个中间件B的执行,然后是中间件C被执行
// 所有的中间件都执行了一遍后,执行Promise.resolve()
// 最里面的中间件C的await next()运行结束,会继续执行console.log("C2")
// 整个中间件C的运行结束又触发了Promise.resolve
// 中间件B开始执行console.log("B2")
// 同理,中间件A执行console.log("A2")
return Promise.resolve(fn(context, () => {
return dispatch(i + 1)
}))
} catch (err) {
return Promise.reject(err)
}
}
return dispatch(0)
}
}

3. 整体回顾

Koa利用了在中间件中间传入next参数的方法,再结合middleware中间件数组和compose组合函数,构建了洋葱圈的中间件执行结构。这也是为什么洋葱圈中间件机制可以运行起来的原因。

洋葱圈的代码并不复杂,但是这种提出问题,带着解决思路去看代码的方式,希望能给大家一点启发。

4. 参考文章

1.《浅析koa的洋葱模型实现》
2.《Koa2 洋葱模型 —— compose 串联中间件的四种实现》
3.《umi-request 网络请求之路》

本文地址:H5W3 » 一篇文章了解洋葱圈模型——看了就忘不掉的那种

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址