koa-application继承自events模块,具有发布-订阅功能

1 events模块需要处理error错误

屏幕快照 2019-11-13 14.35.08.png

2 Koa错误处理屏幕快照 2019-11-13 14.24.29.png

3 源码分析

3.1 错误处理

对应events模块错误处理,至少存在一个error处理函数来兜底,防止node进程挂掉

  1. // application
  2. callback() {
  3. if (!this.listenerCount('error')) this.on('error', this.onerror);
  4. }
  5. // Default error handler
  6. onerror(err) {
  7. if (!(err instanceof Error)) throw new TypeError(util.format('non-error thrown: %j', err));
  8. if (404 == err.status || err.expose) return;
  9. if (this.silent) return;
  10. const msg = err.stack || err.toString();
  11. console.error();
  12. console.error(msg.replace(/^/gm, ' '));
  13. console.error();
  14. }
  15. };

同时可以自定义错误处理程序,参考2中,集中日志处理,可以多次订阅error事件,来处理自己业务错误的处理程序。

  1. app.on('error', err => {
  2. // 错误处理1
  3. });
  4. app.on('error', err => {
  5. // 错误处理1
  6. });
  7. app.on('error', err => {
  8. // 错误处理3
  9. });

3.2 错误触发

在处理请求过程中,如果出错,就会进入promise实例的catch方法,在这个方法里调用context原型上的ctx.onerror方法

  1. // application
  2. handleRequest(ctx, fnMiddleware) {
  3. const res = ctx.res;
  4. res.statusCode = 404;
  5. const onerror = err => ctx.onerror(err);
  6. const handleResponse = () => respond(ctx);
  7. onFinished(res, onerror);
  8. return fnMiddleware(ctx).then(handleResponse).catch(onerror);
  9. }

ctx.onerror里面触发调用application实例emit方法,触发error事件,同时传参(err,ctx),对应2中,出现错误,无发响应,仍然传递当前请求上下文context实例。

  1. // context.js
  2. onerror(err) {
  3. // 前置处理
  4. // delegate
  5. this.app.emit('error', err, this);
  6. // 后置处理
  7. }

fnMiddleware 是koa-compose处理app.middleware后的函数,返回promise实例

  1. // koa-compose
  2. function compose (middleware) {
  3. if (!Array.isArray(middleware)) throw new TypeError('Middleware stack must be an array!')
  4. for (const fn of middleware) {
  5. if (typeof fn !== 'function') throw new TypeError('Middleware must be composed of functions!')
  6. }
  7. /**
  8. * @param {Object} context
  9. * @return {Promise}
  10. * @api public
  11. */
  12. return function (context, next) {
  13. // last called middleware #
  14. let index = -1
  15. return dispatch(0)
  16. function dispatch (i) {
  17. debugger
  18. if (i <= index) return Promise.reject(new Error('next() called multiple times'))
  19. index = i
  20. let fn = middleware[i]
  21. if (i === middleware.length) fn = next
  22. if (!fn) return Promise.resolve()
  23. try {
  24. return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));
  25. } catch (err) {
  26. return Promise.reject(err)
  27. }
  28. }
  29. }
  30. }