60行代码写一个超简陋的koa

发布: 2021-05-12 11:14:48 标签: nodeJs

一个很简陋的koa代码,可以很轻松的了解koa的工作流程

app.js代码

01const http = require('http')
02const { Stream } = require('stream')
03const qs = require('querystring')
04
05const app = {
06 middleware: [],
07 use(fn) {
08 this.middleware.push(fn)
09 },
10 listen(port = 3000) {
11 const server = http.createServer(this.callback.bind(this))
12 return server.listen(port)
13 },
14 async callback(req, res) {
15 console.log('start')
16 const fn = compose(this.middleware)
17 // 这里有很多代理的方法
18 const ctx = {
19 request: req,
20 response: res,
21 req,
22 res,
23 get query() {
24 return { ...qs.parse(req.url.split('?')[1] || '') }
25 },
26 }
27 await fn(ctx)
28 .then(() => {
29 const { body } = ctx
30 if (!body) return res.end('null')
31 if (Buffer.isBuffer(body)) return res.end(body)
32 if (typeof body === 'string') return res.end(body)
33 if (body instanceof Stream) return body.pipe(res)
34 return res.end(JSON.stringify(body))
35 })
36 .catch((error) => {
37 res.end(error.toString())
38 })
39 console.log('end')
40 },
41}
42
43function compose(middleware = []) {
44 let index = -1
45
46 return (ctx, next) => {
47 return dispatch(0)
48 function dispatch(i) {
49 if (i <= index) return Promise.reject(new Error('next() called multile times'))
50 index = i
51 let fn = middleware[i]
52 if (i === middleware.length) fn = next
53 if (!fn) return Promise.resolve()
54 try {
55 return Promise.resolve(fn(ctx, dispatch.bind(null, i + 1)))
56 } catch (err) {
57 return Promise.reject(err)
58 }
59 }
60 }
61}
62
63module.exports = app
64
复制代码

test.js 代码

01// const fs = require('fs')
02const app = require('./app')
03
04app.use(async function test1(ctx, next) {
05 console.log(1)
06 console.log('query', ctx.query)
07 await next()
08 console.log(6)
09})
10app.use(async function test2(ctx, next) {
11 console.log(2)
12 await next()
13 console.log(5)
14})
15app.use(async function test3(ctx, next) {
16 await next()
17 // ctx.body = fs.createReadStream('asset/a.jpg')
18 console.log(4)
19})
20
21app.listen(8000)
22
23console.log('http://localhost:8000')
24
复制代码