美文网首页
从 0 实现一个简易版Koa2

从 0 实现一个简易版Koa2

作者: 风之化身呀 | 来源:发表于2019-07-28 19:25 被阅读0次

1、从一个koa使用的例子开始

const app = new Koa()
app.use( async (ctx,next)=>{
    console.log('a')
    next()
})
app.use( async (ctx,next)=>{
    console.log('b')
    next()
})
app.on('error',err=>console.log(err))
app.listen(3000,()=>console.log('server starting at 3000'))

从这个例子我们大致可以知道需要设计哪些 api:

  • 构造函数 Koa,需要一个成员变量保存中间件函数
  • 需要实现 Koa.prototype.use 方法收集中间件
  • 需要实现Koa.prototype.listen 方法启动服务器并顺序执行所有中间价,附带错误处理

2、简易实现

简易版实现的签名为 DIYKoa

2.1、 基本轮廓

const http = require('http')
const Event = require('events')       // 实现错误监听
// 1、实现构造函数,支持无 new 调用
function DIYKoa(options){  
     if(!(this instanceof DIYKoa)){
         return new DIYKoa(options)
     }
     Event.call(this)
     this.options = options
     this.middlewares = []
}
DIYKoa.prototype = EventEmitter.prototype
DIYKoa.prototype.constructor = DIYKoa

// 2、实现 use 方法收集中间件
DIYKoa.prototype.use = function (fn) {
  if (typeof fn !== 'function') return
  this.middlewares.push(fn)
  return this
}
// 3、实现 listen 方法:启动服务器、处理中间件、错误处理
DIYKoa.prototype.listen = function (...args) {
  const server = http.createServer(this.callback.bind(this)) // callback 是处理中间件依次调用的关键
  server.listen(...args)
}

module.exports = DIYKoa

2.2、实现细节

DIYKoa.prototype.callback = function (req, res) {
  const ctx = this.createContext(req, res) // 封装一下 ctx 对象 , ctx 将会作为中间件函数的 this
  console.log(req.url);
  const handleRequest = () => {
    return res.end('hello world');
  } // 处理中间件执行结果
  const handleError = err => {
    this.emit('error', err)
  } // 触发 error 事件
  const fn = this.compose()
  fn(ctx).then(handleRequest).catch(handleError)
}

DIYKoa.prototype.compose = function () {
  return async ctx => {
    function createNext(middleware, oldNext) {
      return async () => {
        await middleware(ctx, oldNext);
      }
    }
    let len = this.middlewares.length;
    let next = async () => {
      return Promise.resolve();
    };
    for (let i = len - 1; i >= 0; i--) {
      let currentMiddleware = this.middlewares[i];
      next = createNext(currentMiddleware, next);
    }
    await next();
  };
}

DIYKoa.prototype.createContext =(req,res) => {
   // 源码中对 context 做了很丰富的属性代理封装,但这并不是必须的,这里简要处理
   const context = Object.create(null)
   context.req = req
   context.res = res
   return context
}

2.3、验证

// 1、正常情况
const DIYKoa = require('./application.js')
const app = new DIYKoa()
app.use(async (ctx,next)=>{
    console.log('a')
    await next()
})
app.use(async (ctx,next)=>{
    console.log('b')
    await next()
})
app.on('error',err=>console.log(err))
app.listen(3000,()=>console.log('server starting at 3000'))
// 输出,注意这里有个坑,默认会请求两次,一次 / , 一次 /favicon.ico
a b
// 2、异常情况
const DIYKoa = require('./application.js')
const app = new DIYKoa()
app.use(async (ctx,next)=>{
    console.log('a')
    await next()
})
app.use(async (ctx,next)=>{
    throw new Error('error')
    await next()
})
app.on('error',err=>console.log(err))
app.listen(3000,()=>console.log('server starting at 3000'))
// 输出
a
Error error

参考

https://github.com/airuikun/blog/issues/2
https://juejin.im/post/5c7decbbe51d454a7c5e8474

相关文章

  • 从 0 实现一个简易版Koa2

    1、从一个koa使用的例子开始 从这个例子我们大致可以知道需要设计哪些 api: 构造函数 Koa,需要一个成员变...

  • koa框架搭建

    主要是学习了慕课网从0到1打造超好用Web框架 一步到位 掌握KOA2服务端开发的一个总结和复盘。原生的koa2还...

  • koa2 自学笔记(二)

    此系列文章会持续更新。。。 这篇主要讲 koa2 的路由 首先,我们先用 koa2 原生实现一个简单的路由然后再使...

  • Koa2从零搭建完整工程②

    写在前面 看完了廖大神的 JavaScript 教程,特记录一下从0搭建一个完整的 koa2 工程,主要包含: 处...

  • Koa2从零搭建完整工程①

    写在前面 看完了廖大神的 JavaScript 教程,特记录一下从0搭建一个完整的 koa2 工程,主要包含: 处...

  • Python解释器

    1.实现变量相加的简易版

  • 基于AOP和Redis实现的简易版分布式锁(二)

    在上一篇文章基于AOP和Redis实现的简易版分布式锁中我们已经介绍了实现一个简易版的分布式锁。 那么本文主要来讲...

  • Koa 2 初体验(二)

    Koa2 路由 Koa2 原生路由的实现 路由在web中的作用不言而喻,而要先实现原生路由,需要的到地址栏输入的路...

  • 如何实现一个简易版的 Spring - 如何实现 @Compon

    前言 前面两篇文章(如何实现一个简易版的 Spring - 如何实现 Setter 注入[https://mp.w...

  • 第72天 科幻动画制作-09渐变

    制作简易版的从0到最终效果的过程视频 1、去除所有材质与置换,渲染0-70帧白膜视频 2、71~100帧重新打开置...

网友评论

      本文标题:从 0 实现一个简易版Koa2

      本文链接:https://www.haomeiwen.com/subject/xpuvwqtx.html