内容简介:首先我们先简单封装一个模块 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; 复制代码
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 使用四十行代码实现一个精简版 koa
- 遵守 TDD 实现一个精简版的 HashMap
- 实现Pormise,超级精简,一看就能明白Promise的运行原理
- Vuex和Redux都使用的Flux设计模式精简版实现
- 如何精简一本书
- 设计模式精简图册
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Clean Architecture
Robert C. Martin / Prentice Hall / 2017-9-20 / USD 34.99
Practical Software Architecture Solutions from the Legendary Robert C. Martin (“Uncle Bob”) By applying universal rules of software architecture, you can dramatically improve developer producti......一起来看看 《Clean Architecture》 这本书的介绍吧!
HTML 编码/解码
HTML 编码/解码
XML 在线格式化
在线 XML 格式化压缩工具