我是靠谱客的博主 贪玩鞋子,最近开发中收集的这篇文章主要介绍koa2源码剖析和koa-compose实现,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

简介

Koa由 Express 幕后的原班人马打造, 致力于成为 web 应用和 API 开发领域中的一个更小、更富有表现力、更健壮的基石。 通过利用 async 函数,Koa 帮你丢弃回调函数。同时koa的中间件机制和洋葱模型是它独有的特点,并且它没有捆绑任何中间件,而是可以让用户以更优雅的方式去扩展。

Koa是一个精简的web框架,它主要做了以下几件事:

  • 为request和response对象赋能,并基于它们封装成一个context对象,可以通过get,set调用参数
  • 基于async/await的中间件容器机制

源码解读

打开koa的源码,核心文件共四个在lib目录下:

  • application.js
  • context.js
  • request.js
  • response.js

application(初始化)

application是Koa2的入口,里面引入了request.js,response.js,context.js。然后用构造函数的形式,暴露出来。

这里列出主要结构代码:

module.exports = class Application extends Emitter {

  constructor(options) { 
	// xxx
    this.middleware = []; // 注:用来存放通过use函数引入的中间件的数组。
    this.context = Object.create(context); // 注:创建content对象
    this.request = Object.create(request); // 注:同上
    this.response = Object.create(response); // 注:同上
   }
   
  listen(...args) {  // 注:创建node服务实例
    debug('listen');
    const server = http.createServer(this.callback());
    return server.listen(...args);
  }
  
  use(fn) { // 注: 用来把中间件加入到middleware数组里面
	// xxx
    this.middleware.push(fn);
    return this;
  }
  
  callback() {  // 注: 返回一个函数给node服务,作为处理请求的回调函数
    const fn = compose(this.middleware);  // 注: 很重要,将所有的中间件通过compose组合一下,弄成洋葱模型。这里是Koa的精髓部分
 
    if (!this.listenerCount('error')) this.on('error', this.onerror);

    const handleRequest = (req, res) => {
      const ctx = this.createContext(req, res);
      return this.handleRequest(ctx, fn);
    };

    return handleRequest;
  }
  
  handleRequest(ctx, fnMiddleware) { // 注:处理错误
        // xxx
    }
    
  createContext(req, res) { // 注:创建ctx对象,并且把req,res写入ctx
	// xxx 
  }

content

里面都是一堆对参数的set get设置,方便一些参数的获取。

const util = require('util');
const createError = require('http-errors');
const httpAssert = require('http-assert');
const delegate = require('delegates');
const statuses = require('statuses');
const Cookies = require('cookies');

const COOKIES = Symbol('context#cookies');

const proto = module.exports = {
	// xxx 注:一些方法函数,toJosn之类的。
}

// 注:这里就是为了在application.js 里面createContent 的时候,把一些response,request的对象属性代理给content。
delegate(proto, 'response')
  .method('attachment')
  .xxx
  
delegate(proto, 'request')
  .method('acceptsLanguages')
  .xxx

request

module.exports = {
  // 注:基于req封装很多便利的函数和属性,可以让application.js 里面request对象直接调用。
  get header() {
    return this.req.headers;
  },
  
  set header(val) {
    this.req.headers = val;
  },

response

module.exports = {
  // 注:基于res封装很多便利的函数和属性,可以让application.js 里面responset对象直接调用。
   get headers() {
    return this.header;
  },

  get status() {
    return this.res.statusCode;
  },

中间件机制koa-compose

介绍application.js的时候,提到里面有个koa-compose,这里是整个koa框架的精髓。

我们所知的koa中间件是一个洋葱模型:

在这里插入图片描述
现在我们来学习compose是怎么实现洋葱模型的。

要学会洋葱模型,我们必须先要懂一个函数式编程的东西,就是函数合成和函数柯里化。compose就是运用了函数式编程的方式,来实现洋葱模型的。

函数的合成与柯里化

  • 函数合成:

如果一个值要经过多个函数,才能变成另外一个值,就可以把所有中间步骤合并成一个函数,这叫做"函数的合成"(compose)。

const compose = function (f, g) {
  return function (x) {
    return f(g(x));
  };
}
  • 柯理化:

f(x)和g(x)合成为f(g(x)),有一个隐藏的前提,就是f和g都只能接受一个参数。如果可以接受多个参数,比如f(x, y)和g(a, b, c),函数合成就非常麻烦。

这时就需要函数柯里化了。所谓"柯里化",就是把一个多参数的函数,转化为单参数函数。


// 柯里化之前
function add(x, y) {
  return x + y;
}

add(1, 2) // 3

// 柯里化之后
function addX(y) {
  return function (x) {
    return x + y;
  };
}

addX(2)(1) // 3

compose实现

学习完函数式编程之后,我们来实现compose函数。

// compose.js

function compose(middlewares) {
  return function (ctx) {
    return dispatch(0)
    function dispatch(i) {
      let fn = middlewares[i] // 注:application.js 里面用来存放中间件的数组
      if (!fn) { 
        return Promise.resolve()
      }
      return Promise.resolve(fn(ctx,function next() {
        return dispatch(i + 1)
      }))
    }x
  }
}

// 写几个中间件案例:

async function fn1(ctx,next) {
  console.log("fn1"); 
  await next(); 
  console.log("end fn1");
}

async function fn2(ctx,next) {
  console.log("fn2");
  await next();
  console.log("end fn2");
}

function fn3(ctx,next) {
  console.log("fn3");
}


const middlewares = [fn1, fn2, fn3];

const finalFn = compose(middlewares);


finalFn('ctx'); // 注:这里ctx随便用个字符串代替,正式调用的话,ctx是createContent创建的上下文对象,里面有response,request等等。

在这里插入图片描述
洋葱模型,先从外往里面执行,然后再从里往外执行。

  • ① 先执行fn1,打印fn1
  • ② 遇到next函数,fn1后面代码挂起,等待next1执行完毕(这里命名next1,方便理解)
  • ③ next1通过dispatch函数执行fn2
  • ④ 打印fn2
  • ⑤ 遇到next函数,fn2后面代码挂起,等待next2执行完毕
  • ⑥ next2通过dispatch函数执行fn3
  • ⑦ 打印fn3
  • ⑧ 此时fn3函数全部走完,通知fn2,next2已经执行完毕,运行fn2后面代码,打印end fn2
  • ⑨ 此时fn2函数也已经全部走完,再通知fn1,next1已经执行完,运行fn1后面的代码,打印end fn1

到这里一个全部compose就完成了,简单来说这里就是一个Promise嵌套,加上函数式编程。

想看实现的koa2项目代码(application,response,request,compose)可以去我的githubk-koa 看完整项目。

最后

以上就是贪玩鞋子为你收集整理的koa2源码剖析和koa-compose实现的全部内容,希望文章能够帮你解决koa2源码剖析和koa-compose实现所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(64)

评论列表共有 0 条评论

立即
投稿
返回
顶部