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

本文共 4869 字,大约阅读时间需要 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;复制代码

转载地址:http://mocum.baihongyu.com/

你可能感兴趣的文章
使用Eclipse-Maven-git做Java开发(2)--安装maven
查看>>
天猫直通车的相关定义
查看>>
大二第一学期的实训项目
查看>>
python读写配置文件
查看>>
Java String类 contains 函数底层算法
查看>>
ISO7层协议
查看>>
React-Native学习之制作RN版的微博app(一)
查看>>
php OOP面向对象基础
查看>>
juniper srx 远程访问***(dynamic-***)
查看>>
QT开发(五十五)———Qt Quick Controls
查看>>
Java基础学习总结(9)——this关键字
查看>>
Swoole学习笔记(四):WebSocketServer
查看>>
Java基础学习总结(13)——流IO
查看>>
iphone--有关日历中NSDateFormatter中英文
查看>>
grep、egrep简单介绍
查看>>
架构师不可不知的十大可扩展架构
查看>>
我和上帝有个契约
查看>>
PHP知识大全
查看>>
android事件传递机制测试分析
查看>>
dig查记录
查看>>