Skip to content

Instantly share code, notes, and snippets.

@V-Tom
Last active October 30, 2019 06:33
Show Gist options
  • Save V-Tom/64a5607f5eec6fff537221963d4ee294 to your computer and use it in GitHub Desktop.
Save V-Tom/64a5607f5eec6fff537221963d4ee294 to your computer and use it in GitHub Desktop.
koa lite
'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