精简版 koa 简单实现

栏目: Node.js · 发布时间: 5年前

内容简介:首先我们先简单封装一个模块 Application 保证服务的正常运行;首先我们假设我们的 context 是这么一个数据结构:改写 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;

复制代码

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

白话机器学习算法

白话机器学习算法

[新加坡] 黄莉婷、[新加坡] 苏川集 / 武传海 / 人民邮电出版社 / 2019-2 / 49.00元

与使用数学语言或计算机编程语言讲解算法的书不同,本书另辟蹊径,用通俗易懂的人类语言以及大量有趣的示例和插图讲解10多种前沿的机器学习算法。内容涵盖k均值聚类、主成分分析、关联规则、社会网络分析等无监督学习算法,以及回归分析、k最近邻、支持向量机、决策树、随机森林、神经网络等监督学习算法,并概述强化学习算法的思想。任何对机器学习和数据科学怀有好奇心的人都可以通过本书构建知识体系。一起来看看 《白话机器学习算法》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具