node基础:koa2的工作原理是什么

koa2是继express之后,node的又一个主流的web框架,相比于express,koa只保留了核心的中间件处理逻辑,去掉了路由、模版以及一些其他的功能,是一个基于node实现的web框架,特点是优雅、简介、健壮、体积小、表现力去强,它所有的功能都是通过插件的形式来实现的。

koa的原理:

koa是一个基于node实现的web框架,koa通过封装原声的node http模块,koa的context把node的request和response对象封装到单个对象中,并暴露给中间件等调用函数。其最主要的核心是中间件机制洋葱模型。

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

function compose(middleware) {
    return () => {
        return dispatch(0)
        function dispatch(i) {
            let fn = middleware[i]
            if (!fn) {
                return Promise.resolve()    
            }
            return Promise.resolve(function next() {
                return dispatch(i + 1)
            })
        }
    }
}

核心代码就是return Promise.resolve(fn(context, dispatch.bind(null, i+1)));递归遍历,直到所有的中间件next,生成一个多层嵌套的promise函数。

koa中间件处理可以当作是洋葱模型。中间件数组中中间件的执行是通过递归的方式来执行的,调用dispatch函数,从第一个开始执行,当有next方法时,创建promise,等到下一个中间件执行结果再执行next后端的代码,。当第二个中间件也执行next方法的时候,依然会创建promise,等待下一个中间件执行结果这也就是中间件的next的执行原理,app.use()将中间件push到中间件数组中,然后在listen方法中通过调用compose方法进行集中处理。

koa的基本组成:

application.js: application负责管理中间件的处理,以及请求的处理

context.js:context维护了一个请求的上下文

request.js:requset对req做了抽象和封装

response.js: response对res做了抽象封装

Application:主要是用于维护中间件以及一些其他的环境

module.export = class Application extends Emitter {
    constructor () {
        super()
        this.proxy = false
        this.middleware = []
        this.subdomainOffect = 2
        this.env = process.env.NODE_ENV || 'development'
        this.context = Object.create(context)
        this.request = Object.create(request)
        this.response = Object.create(response)
    }
}

通过app.use(fn)可以将fn添加到中间件列表this.middleware中.

app.listen的方法源码:

listen () {
    const server = http.createServer(this.callback)
    return server.listen.apply(server, arguments)
}

首先通过this.callback方法返回一个函数作为http.createServer的回掉函数,然后进行监听,我们已经知道,http.createServer的回掉接受俩个参数,req和res,下面就是this.callback的实现:

callback () {
    const fn = compose(this.middleware)
    if (!this.listeners('error').length) this.on('error', this.onerror)
    return (req, res) => {
        res.statusCode = 404
        const ctx = this.createContext(req, res)
        onFinshed(res, ctx.onerror)
        fn(ctx).then(() => respond(ctx)).catch(ctx.onerror)
    }
}

首先将所有的中间件通过compose组合成一个函数,然后返回http.createServer所需要的回掉函数,于是我们可以看到,当服务器收到一个请求的时候会使用req和res通过this.createContext方法来创建上下文环境ctx,然后使用fn来进行中间件的逻辑处理。

context:

当请求到来的时候,会通过req和res来创建一个context(ctx),然后执行中间件。实际上,在创建context的时候,还会创建request和response。

最左边表示每个文件到处的对象

中间一列表示每个koa应用以及维护的属性

右边的俩列表示对应的每个请求维护的对象

黑色的线表示实例化

红色的线表示原型链

蓝色的线表示属性

实际上,ctx主要的功能是代理处理requset和response的功能,提供了对request和response对象的边界访问能力,源码:

delegate(proto, 'response')
    .method('attchment')
    .access('status')
    .getter('writable')
delegate(proto, 'request')
    .method('acceptsLanguages')
    .access('quserystring')
    .getter('ip')

这里通过delegates模块来实现属性的访问代理,简单来说,通过delegate(proto, 'response')当访问proto的代理属性的时候,实际访问的是proto.response的对象属性。

中间件的执行

我们知道所有的中间件都会经过compose的处理,返回一个新的函数,源码:

function componse(middleware) {
    if (!Array.isArray(middleware)) throw new Error('middleware stack must be an array')
    for(const fn of middleware) {
        if (typeof fn !== 'function') throw new Error('middleware must be componsed of functions')
    }
    return function (context, next) {
        let index = -1
        return dispatch(0)
        function dispatch(i) {
            if (i <= index) return Promise.reject(new Error('next() called multip times')) 
            index = i
            let fn = middleware[i]
            if (i === middleware.length) fn = next
            if (!fn) retrun Promise.resolve()
            try {
                return Promise.resolve(fn(context, function next () {
                    return dispatch(i + 1)
                }))
            }
            catch(err) {
                return Promise.reject(err)
            }
        }
    }
}

koa的中间件支持普通函数,返回一个Promise函数,以及async/await函数,由于generator函数中间件在新版本中不在支持,因此不建议使用。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值