博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
精简版 koa 简单实现
阅读量:4087 次
发布时间:2019-05-25

本文共 4971 字,大约阅读时间需要 16 分钟。

一、 Application 模块的简单封装

首先我们先简单封装一个模块 Application 保证服务的正常运行;

  • 初始化一个项目
$ npm init -y...复制代码
  • 创建文件 application.js 并并编写如下代码;
const http = require('http');class Application{  // 初始化  constructor(){    this.callback = () => {}  }  // 设置回调函数  use(callback){    this.callback = callback;  }  // listen 创建服务并对服务进行监听  listen(...args){    const server = http.createServer((req, res) => {      this.callback(req, res);    });    server.listen(...args);  }}module.exports = Application;复制代码
  • 创建 server.js 文件,调用 Application 模块起一个服务:
const Application = require('./application.js');const app = new Application();app.use((req, res) => {  res.writeHead(200);  res.end('hello world');});app.listen(3000, () => {  console.log('监听端口:3000');});复制代码

二、 Application 模块挂载 context

首先我们假设我们的 context 是这么一个数据结构:

  • context 中挂载了 request response req res, 同时还有抽离的额外属性 url body
  • request 中挂载了 req, 同时还有抽离的额外属性 url
  • response 中挂载了 res, 同时还有抽离的额外属性 body
context: {  url: String,  body: String,  request: {    url: String,    req: Object  },  response: {    body: String,    res: Object  },  req: Object,  res: Object}复制代码

改写 Application

  • 设计 context request response 原型数据结构;
  • 将 context request response 原型数据结构挂载到 Application
  • 编写函数创建 context
  • 改写回调函数的调用方式;
const http = require('http');// [1]构建数据结构(作为原型使用)const request = {  // 因为后期 request 将会挂载上 req 所以存在 this.req  get url(){    return this.req.url;  }};const response = {  get body(){    return this._body;  },  set body(val){    this._body = val;  }};const context = {  // 因为后期 context 将会挂载上 request response 所以存在 this.request 和  this.response  get url(){    return this.request.url;  },  get body(){    return this.response.body;  },  set body(val){    this.response.body = val;   }}class Application{  constructor(){    this.callback = () => {},    // [2]将原型挂载到 Application    this.context = context;    this.request = request;    this.response = response;  }  use(callback){    this.callback = callback;  }  // [3]创建 context 函数,挂载上 request response req res   createCtx(req, res){    const ctx = Object.create(this.context);    ctx.request = Object.create(this.request);    ctx.response = Object.create(this.response);    ctx.req = ctx.request = req;    ctx.res = ctx.response = res;    return ctx;  }  listen(...args){    const server = http.createServer((req, res) => {      // [4]创建 context, 并进行简单修改      const ctx = this.createCtx(req, res);      this.callback(ctx);      ctx.res.end(ctx.body);    });    server.listen(...args);  }}module.exports = Application;复制代码

修改 server.js 中 Application 的引用

const Application = require('./application.js');const app = new Application();app.use( ctx => {  ctx.body = 'hello world'});app.listen(3000, () => {  console.log('监听端口:3000');});复制代码

三、 中间件的实现

3.1 洋葱模型实现

// 场景模拟// 异步 promise 模拟const delay = async () => {  return new Promise((resolve, reject) => {    setTimeout(() => {      resolve();    }, 2000);  });}// 中间间模拟const fn1 = async (ctx, next) => {  console.log(1);  await next();  console.log(2);}const fn2 = async (ctx, next) => {  console.log(3);  await delay();  await next();  console.log(4);}const fn3 = async (ctx, next) => {  console.log(5);}const middlewares = [fn1, fn2, fn3];// compose 实现洋葱模型const compose = (middlewares, ctx) => {  const dispatch = (i) => {    let fn = middlewares[i];    if(!fn){ return Promise.resolve() }    return Promise.resolve(fn(ctx, () => {      return dispatch(i+1);    }));  }  return dispatch(0);}compose(middlewares, 1);复制代码

3.2 compose 函数在 Application 模块中的使用:

const http = require('http');const request = {  get url(){    return this.req.url;  }};const response = {  get body(){    return this._body;  },  set body(val){    this._body = val;  }};const context = {  get url(){    return this.request.url;  },  get body(){    return this.response.body;  },  set body(val){    this.response.body = val;   }}class Application{  constructor(){    this.context = context;    this.request = request;    this.response = response;    // 初始化中间件数组    this.middlewares = [];  }  // 通过push的方式进行添加中间件  use(middleware){    this.middlewares.push(middleware);  }  createCtx(req, res){    const ctx = Object.create(this.context);    ctx.request = Object.create(this.request);    ctx.response = Object.create(this.response);    ctx.req = ctx.request = req;    ctx.res = ctx.response = res;    return ctx;  }  // compose 函数  compose(middlewares, ctx){    const dispatch = (i) => {      const fn = middlewares[i];      if(!fn){        return Promise.resolve();      }else{        return Promise.resolve(fn(ctx, () => {          dispatch(i +1 );        }));      }    }    return dispatch(0);  }  listen(...args){    // 改用 async await 并调用compose    const server = http.createServer(async (req, res) => {      const ctx = this.createCtx(req, res);      await this.compose(this.middlewares, ctx);      ctx.res.end(ctx.body);    });    server.listen(...args);  }}module.exports = Application;

作者:qianyin925
链接:https://juejin.im/post/5c0b8a08f265da612c5db4ea
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

你可能感兴趣的文章
UML 类图基本图示法
查看>>
Github免费账户使用”私有库“
查看>>
设计模式 策略模式
查看>>
设计模式 单一职责原则
查看>>
设计模式 开放-封闭原则
查看>>
设计模式 依赖倒转原则 & 里氏代换原则
查看>>
设计模式 装饰模式
查看>>
设计模式 代理模式
查看>>
设计模式 工厂方法模式
查看>>
设计模式 原型模式与C++ & 设计模式的思考
查看>>
设计模式 模板方法模式
查看>>
设计模式 迪米特法则
查看>>
设计模式 外观模式
查看>>
游戏人工智能 状态驱动智能体设计——有限状态机(FSM)
查看>>
游戏人工智能 状态驱动智能体设计——消息功能
查看>>
C++ extern关键字
查看>>
C++ __asm关键字
查看>>
关于STL erase的iterator失效问题
查看>>
泡泡堂 DirectX11 Demo 2016.8.14 v1.2更新
查看>>
算法导论 简单顺序栈
查看>>