综合开发

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

微信扫一扫,分享到朋友圈

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来的,在 koa
listen的时候会编译这些插件,其中 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一个实例,中间件的规范,自己想开发一个中间件该如何写,最后是编译所有的中间件,是如何做的,再着服务启动。看完,我的之后,你可以自己按照这个流程去研究研究。哈哈,表达能力太差。

浅聊事件循环:宏任务和微任务

上一篇

基于Kotlin + Jetpack全家桶 + Coroutines(协程) 等架构实现的一款精简版Github客户端项目。

下一篇

你也可能喜欢

评论已经被关闭。

插入图片

热门栏目

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

长按储存图像,分享给朋友