Koa2启动过程都做了什么-源码读阅

前言

是第一次写,是第一次写,是第一次写,重要的事说三遍,也想通过文章的形式记录下自己的学习历程,如果内容错误或有好的方法,还请各位老铁果断指出,自己会及时改正。

准备工作

下面是一个简单的koa启动代码,从实例化koa到最后监听端口的整个过程

const Koa2 = require('koa2')
const Router = require('koa2-router')
const  app = new Koa2()
const router = new Router()
app.use(router)
router.get('/', (ctx)=>{
    ctx.body = '这是一个测试'
})
app.listen(3000,()=>{
    console.log('port 3000 listing')
})
第一个: new Koa2()源码是如何的,做了啥?

初始化操作,中间件,上下文context,以及请求,和响应request,response,其中可以看的就是Object.create(),创建的对象,可以看下它们引入的对象,里面都初始化那些东西,最后listen都会挂载到ctx属性上。

 constructor(server) {
    super();
    this.server=server
    this.proxy = false;
    this.middleware = [];
    this.subdomainOffset = 2;
    this.env = process.env.NODE_ENV || 'development';
    this.context = Object.create(context);
    this.request = Object.create(request);
    this.response = Object.create(response);
  }
第二个:new Router()

作为中间件的路由,初始化不同就是 它返回是个router方法,为啥要返回呢,因为koa使用中间件都是通过use来的,在koalisten的时候会编译这些插件,其中ctx,next,都会通过参数的方式,传进来,所以为啥理解要这样了。

function Router(options) {
  if (!(this instanceof Router)) {
    return new Router(options)
  }
  var opts = options || {}
  function router(ctx, next) {
    // patch context/request prototype
    patchPrototype(ctx.app)
    // initialize ctx.req with `originalUrl`, `baseUrl`, `params`
    const req = ctx.req
    req.originalUrl = req.originalUrl || req.url
    req.baseUrl = req.baseUrl || ''
    req.params = req.params || {}
    req.matched = req.matched || []
    return router.handle(ctx, next)
  }
  router._name = (typeof opts === 'object' ? opts.name : opts) || 'router'
  // inherit from the correct prototype
  setPrototypeOf(router, this)
  router.caseSensitive = opts.caseSensitive
  router.mergeParams = opts.mergeParams
  router.strict = opts.strict
  router.methods = opts.methods || [
    'HEAD',
    'OPTIONS',
    'GET',
    'PUT',
    'PATCH',
    'POST',
    'DELETE'
  ]
  router.params = {}
  router.stack = []
  if (!Array.isArray(router.methods)) {
    throw new TypeError('invalid options.methods, got type ' + gettype(opts.methods))
  }
  // we should never return 501 for GET/HEAD method
  // so we need to ensure router.methods contains at least GET and HEAD
  if (!~router.methods.indexOf('GET')) router.methods.push('GET')
  if (!~router.methods.indexOf('HEAD')) router.methods.push('HEAD')
  return router
}
第三个: app.use()

添加koa中间件,没毛病

 use(fn) {
    if (typeof fn !== 'function') throw new TypeError('middleware must be a function!');
    if (isGeneratorFunction(fn)) {
      deprecate('Support for generators will been removed in v3. ' +
                'See the documentation for examples of how to convert old middleware ' +
                'https://github.com/koajs/koa/tree/v2.x#old-signature-middleware-v1x---deprecated');
      fn = convert(fn);
    }
    debug('use %s', fn._name || fn.name || '-');
    this.middleware.push(fn);
    return this;
  }
第四个:处理所有的koa中间件

在koa-compose文件中的index.js文件 33行,编译所有的中间件,其中下面代码的原理就是通过递归遍历所有用到的中间件,通过promise实现异步处理

  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, function next () {
          return dispatch(i + 1)
        }))
      } catch (err) {
        return Promise.reject(err)
      }
    }
  }

总结

感觉不知道怎么表达,不知是知识太少了还是怎么,还得练练,我感觉我总体想表达的,就是koa从new一个实例,中间件的规范,自己想开发一个中间件该如何写,最后是编译所有的中间件,是如何做的,再着服务启动。看完,我的之后,你可以自己按照这个流程去研究研究。哈哈,表达能力太差。

https://juejin.im/post/5e7b4719e51d4526ed66dd35

「点点赞赏,手留余香」

    还没有人赞赏,快来当第一个赞赏的人吧!
0 条回复 A 作者 M 管理员
    所有的伟大,都源于一个勇敢的开始!
欢迎您,新朋友,感谢参与互动!欢迎您 {{author}},您在本站有{{commentsCount}}条评论