Koa洋葱原型源码解读
版本:2.13.1
application.js
构造函数
1 | constructor(options) { |
有一个middleware
存函数
use方法
1 | use(fn) { |
每次使用app.use()就会吧回调函数push到middleware
里
listen方法
1 | listen(...args) { |
创建一个服务,执行callback方法
callback和handleRequest方法
1 | callback() { |
compse函数返回一个中间件函数,在handleRequest执行中间件函数,如果全部 resolve 了就可以调用 handleResponse 发送给客户端
本片博客的重点就是compose是怎么实现koa的洋葱模型的
koa-compose.js
1 | app.use(async (ctx, next) => { |
compose函数
1 | function compose (middleware) { |
compose
函数接收middleware
数组,dispatch(0)
即开始分发一号中间件。dispatch(0)
内部,此时 fn 为一号中间件,会走到 try/catch 块,尝试执行Promise.resolve(fn(context, dispatch.bind(null, i + 1)))
,即一号中间件此时获得入参context
、dispatch(1)
。一号中间件开始执行,遇到 next()(即dispatch(1)),控制权移交,执行 dispatch(1),此时二号中间件获得入参
context
、dispatch(2)
。二号中间件开始执行,执行到
await next()
时,再重复上述逻辑,dispatch(2),但是这一次会停在这里:1
2
3let fn = middleware[i];
if (i === middleware.length) fn = next;
if (!fn) return Promise.resolve();fn = next,这里的 next 由于并没有值,所以会直接 return 一个立即 resolve 的 Promise。也就是说二号中间件内部的 await next()会立刻返回。
二号中间件做完自己的事后,相当于一号中间件内部的
await next()
返回了,因此控制权就归还给一号中间件。
如果中间件中的next()
方法报错了怎么办。
1 | ctx.onerror = function { |
答:中间件链错误会由ctx.onerror
捕获,该函数中会调用this.app.emit('error', err, this)
(因为koa
继承自Emitter
,所以有emit
和on
等方法),可以使用app.on('error', (err) => {})
,或者app.onerror = (err) => {}
进行捕获。
参考文章
https://juejin.cn/post/6844904088220467213#heading-16
https://linbudu.top/posts/2020/02/25/koa%E6%BA%90%E7%A0%81%E7%B2%BE%E8%AF%BB.html#new-%E4%B8%80%E4%B8%AA-koa-%EF%BC%8C%E5%8F%91%E7%94%9F%E4%BA%86%E4%BB%80%E4%B9%88%EF%BC%9F