Last active
October 30, 2019 06:33
-
-
Save V-Tom/64a5607f5eec6fff537221963d4ee294 to your computer and use it in GitHub Desktop.
koa lite
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict' | |
const http = require('http') | |
const Emitter = require('events') | |
module.exports = class KoaLite extends Emitter { | |
constructor() { | |
super() | |
this.middleware = [] | |
} | |
/** | |
* 添加 中间件 | |
* @param generatorFunction | |
* @returns {KoaLite} | |
*/ | |
use(generatorFunction) { | |
this.middleware.push(generatorFunction) | |
return this | |
} | |
/** | |
* 开始监听服务 | |
* @returns {*} | |
*/ | |
listen() { | |
const server = http.createServer(this.listenCallBack()) | |
return server.listen.apply(server, arguments) | |
} | |
/** | |
* 监听服务核心回调 | |
*/ | |
listenCallBack() { | |
// 创建一个 middleware queue 控制器 | |
const fn = compose(this.middleware) | |
return (req, res) => { | |
// 默认 http status 404 | |
res.statusCode = 404 | |
// 创建一个 context 上下文 | |
const ctx = this.createContext(req, res) | |
// 处理错误 | |
const onerror = err => console.error(err) | |
// 处理响应内容 | |
// 这里简单的直接 res.end(...) | |
const handleResponse = () => ctx.res.end(ctx.body || 'hello koa lite') | |
// 发射 | |
fn(ctx).then(handleResponse).catch(onerror); | |
} | |
} | |
/** | |
* 创建上下文 | |
* @returns {Object} | |
*/ | |
createContext(req, res) { | |
// 创建一个简单的上下文 | |
const context = Object.create(null) | |
context.req = req | |
context.res = res | |
return context | |
} | |
/** | |
* Event Emitter 错误处理 | |
* @param err | |
*/ | |
onError(err) { | |
if (404 == err.status || err.expose) return; | |
const msg = err.stack || err.toString(); | |
process.stdout.write(msg.replace(/^/gm, ' ')) | |
} | |
} | |
/** | |
* compose | |
* @param middleware | |
* @returns {Function} | |
*/ | |
function compose(middleware) { | |
return function (context, next) { | |
let index = -1 | |
return dispatch(0) | |
function dispatch(i) { | |
if (i <= index) return Promise.reject(new Error('next() called multiple times')) | |
index = i | |
let fn = middleware[i] | |
if (i === middleware.length) fn = next | |
if (!fn) return Promise.resolve() | |
try { | |
// 这里并没有自动 next | |
// 使用了中间件需要手动 next 或者 await next() | |
return Promise.resolve(fn(context, function next() { | |
return dispatch(i + 1) | |
})) | |
} catch ( err ) { | |
return Promise.reject(err) | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment