资讯专栏INFORMATION COLUMN

koa2源码分析

ningwang / 3186人阅读

摘要:下面基于构造函数入口做进一步分析。创建一个空数组存放放,洋葱流程的真相下面会分析法到决定忽略的子域名数量,默认为处理环境变量实例上挂载说明上面是构造函数入口启动入口如下借用原生,添加。

引言

最近在写koa2相关例子,顺便看了下koa2的源码,下面是一些个人理解。

koa1核心基于generator,但是严重依赖co的包装。koa2完全不需要,基于async(其实质是generator的语法糖调用包装),在node v7 下可直接运行。
关于async和generator的语法,本文不做赘述。下面先创建一个koa实例,然后基于入口一步步分析。

//koa code
const Koa=require("koa");
const app=new Koa();

app.use(async function (ctx, next) {
    console.log(">> one");
    await next();
    console.log("<< one");
});
app.use(ctx => {
    ctx.body="hello world gcy";
});
app.listen("3000",function () {
    console.log("listening on port 3000");
});

说明 上面这段代码似乎有些神秘,其实质是下面http module的封装调用。

// native code
let http=require("http");
let server=http.createServer(function (req,res) {
    res.writeHead(200,{"Content-type":"text/plain"});
    res.write("hello world gcy");
    res.end();
});
//start service listen
server.listen(8000,function () {
    console.log("listening on port 8000");
});

下面基于koa构造函数入口做进一步分析。

constructor() {
    super();

    this.proxy = false;
    //创建一个空数组存放放middleware,洋葱流程的真相,下面会分析法到
    this.middleware = [];
    //决定忽略的子域名数量,默认为2
    this.subdomainOffset = 2;
    //处理环境变量
    this.env = process.env.NODE_ENV || "development";
    //实例上挂载context,request,response
    this.context = Object.create(context);
    this.request = Object.create(request);
    this.response = Object.create(response);
  }

说明 上面是构造函数入口,启动入口如下

 //借用原生http.createServer,添加app.callback。
  listen() {
    debug("listen");
    const server = http.createServer(this.callback());
    return server.listen.apply(server, arguments);
  }

说明 通过上面两个步骤一个完整的web服务器建立起来。对于监听接受到的请求解析处理,是通过callback函数,调用一系列中间件来完成。
下面分析中间件执行流程,我认为koa的主要内涵也就在这,所以做一下重点来论述。
首先引入经典中间件洋葱图,以便理解。

结合这幅图再看下面的代码

////核心代码application 126 行  const fn = compose(this.middleware);
 return function (context, next) {
    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
      //立即返回处于resolve状态promise实例,以便后续逻辑继续执行
      if (!fn) return Promise.resolve()
      try {
     
        //   await next();  //当fn里面执行这句话时,就会执行dispatch(i+1),导致洋葱执行过程
        //   整个过程类似堆栈执行释放过程中的的递归调用,虽然有差异,可借用类比思考其执行顺序流程
        return Promise.resolve(fn(context, function next () {
          return dispatch(i + 1)
        }))
      } catch (err) {
        return Promise.reject(err)
      }
    }
    // 核心代码application 136 行 return fn(ctx)[是一个立即状态的promise].then(handleResponse).catch(onerror);
  }
}

如果结合注释看上述代码过程中存在疑惑,可进一步参考下面的进行思考,反之忽略即可。

const Koa=require("koa");
const app=new Koa();


app.use(async function (ctx, next) {
    console.log(">> one");
    await next();
    console.log("<< one");
});
app.use(async function (ctx, next) {
    console.log(">> two");
    ctx.body = "two";
    await next();
    console.log("<< two");
});
app.use(async function (ctx, next) {
    console.log(">> three");
    await next();
    console.log("<< three");
});
//如果放到首部,不方便理解洋葱执行流程,因为没有调用next函数
app.use(ctx => {
    ctx.body="hello world gcy";
});
app.listen("3000",function () {
    console.log("listening on port 3000");
});

说明 koa基于中间价架构,核心简洁,除此之外还有一些其它相对重要的方法。

application.js

use(fn) //组装use的传参

createContext(req, res) 创建初始化的上下文,将req和res挂载在context上

onerror(err) 错误处理,当设定this.slient为true,不会输出信息,在emit触发时执行

respond(ctx) http response简单封装,信息返回

context.js

delegate(proto, "request") //Request相关方法委托,从而让context作为调用入口

onerror(err) //中间件执行过程中异常处理逻辑

除此之外还有request和response的参数解析文件,因为逻辑简单,不做叙述。
虽然核心文件不多,但是其也require了不少包,下面列举几个比较重的,以作为示例。

require

events application继承自Emitter,从而可以实现事件的订阅发布。

koa-compose 中间件的封装,核心逻辑之一,上面已分析。

debug 错误信息格式封装处理

statuses http状态码和和相应信息对应处理

koa-convert 把generator转为promise

…… and so on

总结

写这篇文章起因,是在写case的过程中,同一解决方案下中间件选择的纠结症,尤其是在选择render template过程中,为找其本质间差异,探寻到此。
源码分析基于koa(version 2.2.0),通读源码之后,可以较清晰的开发或者使用别人的中间件,
如果你有不同的理解,欢迎留言交流。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/82202.html

相关文章

  • koa2 一网打尽(基本使用,洋葱圈,中间件机制和模拟,源码分析(工程,核心模块,特殊处理),核心点

    摘要:洋葱圈处理模型。基于的灵活强大的中间件机制。参考官网提供的基本,不在赘述部分实现,参考源码分析常用服务端口监听返回适用于方法的回调函数来处理请求。 本文 github 地址: https://github.com/HCThink/h-blog/blob/master/source/koa2/readme.md github 首页(star+watch,一手动态直达): https:...

    william 评论0 收藏0
  • Koa源码阅读笔记(4) -- ctx对象

    摘要:本笔记共四篇源码阅读笔记源码阅读笔记源码阅读笔记服务器启动与请求处理源码阅读笔记对象起因前两天终于把自己一直想读的源代码读了一遍。首先放上关键的源代码在上一篇源码阅读笔记服务器启动与请求处理中,我们已经分析了的作用。 本笔记共四篇Koa源码阅读笔记(1) -- coKoa源码阅读笔记(2) -- composeKoa源码阅读笔记(3) -- 服务器の启动与请求处理Koa源码阅读笔记(4...

    ityouknow 评论0 收藏0
  • 通过实例分析javascript中的“中间件”

    摘要:如果验证没出现问题,就注册这个中间件并放到中间件数组中。但如果不执行,中间件的处理也会终止。整理下流程默认会执行中间件数组中的第一个,也就是代码中的,第一个中间件通过返回的是第二个中间件的执行。 介绍 如果你使用过redux或者nodejs,那么你对中间件这个词一定不会感到陌生,如果没用过这些也没关系,也可以通过这个来了解javascript中的事件流程。 一个例子 有一类人,非常的懒...

    zhangyucha0 评论0 收藏0
  • react + koa2实现的论坛

    摘要:页面预览页面主要分为话题列表页消息页面个人信息页面创建话题页面个人设置页面注册页面登陆页面页面。还有权限方面的,比如登陆后不可以再进入登陆页面,未登陆也不可以进入创建主题页面。没有使用,但推介使用,不然性能不好。 技术栈 线上地址:点击查看 (访问会有点慢,至于原因,下面会说明)前端(主要):reactv15.6.1、react routerv4.2.0、reduxv3.7.2、ant...

    jk_v1 评论0 收藏0
  • KOA2框架原理解析和实现

    摘要:实现的四大模块上文简述了源码的大体框架结构,接下来我们来实现一个的框架,笔者认为理解和实现一个框架需要实现四个大模块,分别是封装创建类构造函数构造对象中间件机制和剥洋葱模型的实现错误捕获和错误处理下面我们就逐一分析和实现。 什么是koa框架?        koa是一个基于node实现的一个新的web框架,它是由express框架的原班人马打造的。它的特点是优雅、简洁、表达力强、自由度...

    tracymac7 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<