洋葱模型 Published on Dec 15, 2020 in 前端javascriptnodejs with 0 comment 用过koa的同学都应该知道洋葱模型这个概念,今天我们来聊下洋葱模型,分两步走,一:看下洋葱模型的效果,能做什么;二:实现一个洋葱模型 #### 洋葱模型效果  这里我们定义tar对象,现在我们执行下面代码 ```js tor.use((ctx, next) => { console.log(1) next() console.log(2) }) tor.use((ctx, next) => { console.log(3) next() console.log(4) }) tor.use((ctx, next) => { console.log(5) next() console.log(6) }) ``` 输出结果是这样的: ``` 1 3 5 6 4 2 ``` #### 异步情况 ```js tor.use(async (ctx, next) => { console.log(1) await next() console.log(3) }) tor.use(async (ctx, next) => { const result = await (new Promise(resolve => { setTimeout(() => { resolve(2) }, 1000) })) console.log(result) next() }) ``` 输出结果是这样的: ``` 1 2 3 ``` #### 洋葱原理实现 现在我们来看下它的实现原理。每次调用use方法的时候就会将这个方法放到一个数组中,执行的时候再从数组中递归逐个调用,先来看下这块的核心代码: ```js function compose (middlewares, ctx) { function dispatch (index) { if (index === middlewares.length) return const middleware = middlewares[index] middleware(ctx, () => dispatch(index + 1)) } dispatch(0) } ``` > `middlewares`是存放函数的数组 > > 这里的`() => dispatch(index + 1)`就是`next` 执行如下代码,看输出结果 ```js const middlewares = [] middlewares.push(function (ctx, next) { console.log(1) next() console.log(2) }) middlewares.push(function (ctx, next) { console.log(3) next() console.log(4) }) middlewares.push(function (ctx, next) { console.log(5) next() console.log(6) }) compose(middlewares, {}) ``` 输出的结果是: ``` 1 3 5 6 4 2 ``` 实现是实现了,好像异步还不行,现在我们来处理异步实现 修改compose方法 ```js function compose(middlewares, ctx) { function dispatch (index) { if (index === middlewares.length) { return Promise.resolve() } let middleware = middlewares[index] return Promise.resolve(middleware(ctx, () => dispatch(index + 1))) } return dispatch(0) } ``` 修改好了,现在执行下面的代码: ```js const middlewares = [] middlewares.push(async (ctx, next) => { console.log(1) await next() console.log(3) }) middlewares.push(async (ctx, next) => { const result = await (new Promise(resolve => { setTimeout(() => { resolve(2) }, 1000) })) console.log(result) next() }) compose(middlewares, {}) ``` 输出结果如下: ``` 1 2 // 1秒之后 3 ``` 本文由 tutustack 创作,采用 知识共享署名4.0 国际许可协议进行许可本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名