# Koa2

Koa 是一个新的 web 框架,由 Express 幕后的原班人马打造, 致力于成为 web 应用和 API 开发领域中的一个更小、更富有表现力、更健壮的基石。 通过利用 async 函数,Koa 帮你丢弃回调函数,并有力地增强错误处理。 Koa 并没有捆绑任何中间件, 而是提供了一套优雅的方法,帮助您快速而愉快地编写服务端应用程序。

https://koa.bootcss.com/

koa2封装了原生的node http模块,koa的Context吧Node的Request对象和Response对象封装到单个对象中,并且暴露给中间件等回调函数

最主要的核心是 中间件机制洋葱模型

# 源码

源码中主要就是四个文件

WechatIMG80

# 中间件机制洋葱模型

WechatIMG81

通过use()注册多个中间件放入数组中,然后从外层开始往内执行,遇到next()后进入下一个中间件,当所有的中间件执行完后,开始返回,一次执行中间件中未执行的部分,整体流程就是递归处理

# koa-compose

'use strict'

/**
 * Expose compositor.
 */

module.exports = compose

/**
 * Compose `middleware` returning
 * a fully valid middleware comprised
 * of all those which are passed.
 *
 * @param {Array} middleware
 * @return {Function}
 * @api public
 */

function compose (middleware) {
  if (!Array.isArray(middleware)) throw new TypeError('Middleware stack must be an array!')
  for (const fn of middleware) {
    if (typeof fn !== 'function') throw new TypeError('Middleware must be composed of functions!')
  }

  /**
   * @param {Object} context
   * @return {Promise}
   * @api public
   */

  return function (context, next) {
    // last called middleware #
    let index = -1
    return dispatch(0)
    function dispatch (i) {
      if (i <= index) return Promise.reject(new Error('next() called multiple times'))
      index = i
      let fn = middleware[i]
      if (i === middleware.length) fn = next
      if (!fn) return Promise.resolve()
      try {
        return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));
      } catch (err) {
        return Promise.reject(err)
      }
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

# 简单的实现一个koa

const EventEmitter = require('events');
const http = require('http');

class Application extends EventEmitter {
    constructor(){
        super();
        this.middlewares = [];
    }
    use(middleware){
        this.middlewares.push(middleware);
    }
    listen(...args) {
        const server = http.createServer(this.callback());
        server.listen(...args);
    }
    callback() {
        return (req,res) => {
            // console.log(req,res);
            // res.end('hello memory');
            let fn = this.compose()
            const ctx = {};
            const onerror = this.onerror
            return fn(ctx).then(()=>{
                res.end('hello memory')
            }).catch(onerror)
        }
    }
    compose() {
        return async (ctx)=>{
            function createNext (middleware,oldNext) {
              return async ()=>{
                 await  middleware(ctx,oldNext);
              }
            }
            let len = this.middlewares.length;
            let next = async ()=>Promise.resolve();//初始值,洋葱模型的中心
            for(let i=len-1;i>=0;i--){
              let currentMiddleware = this.middlewares[i]
              next = createNext(currentMiddleware,next)
            }
            await next();
        }
    }
    onerror (err,ctx) {
        // this.emit(err)
        console.log(err)
    }
}

module.exports = Application;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50