简介

koa2 学习笔记。

koa2 中间件原理

模拟实现

// == Application.js
const http = require('http');

// == 对象属性的 get 和 set 方法
let request = {
    get url() {
        return this.req.url;
    }
};
let response = {
    get body() {
        return this._body;
    },
    set body(val) {
        this._body = val;
    }
};
let 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.middleware = [];
    }

    // == 封装 HTTP 模块
    listen(...args) {
        const server = http.createServer(async (req, res) => {
            let ctx = this.createCtx(req, res);
            const middlewaresFn = this.compose(this.middleware);
            await middlewaresFn(ctx);
            ctx.res.end(ctx.body);
        });
        server.listen(...args);
    }

    // == 封装 ctx 对象
    createCtx(req, res) {
        let ctx = Object.create(this.context);
        ctx.request = Object.create(this.request);
        ctx.response = Object.create(this.response);
        ctx.req = ctx.request.req = req;
        ctx.res = ctx.response.res = res;
        return ctx;
    }

    // == 收集中间件
    use(callback) {
        this.middleware.push(callback);
    }

    // == 中间件执行机制
    compose(middleware) {
        if (!Array.isArray(middleware)) throw new TypeError('Middleware stack must be an array!')
        for (const fn of middleware) {
            if (typeof fn !== 'function') throw new TypeError('Middleware must be composed of functions!')
        }
        return function (context) {
            let index = -1;
            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 {
                    return Promise.resolve(
                      // == 函数内部调用自身函数: 里面传入第二个中间件
                      fn(context, function next() {
                        return dispatch(i + 1);
                      })
                    );
                } catch (err) {
                    return Promise.reject(err);
                }
            }
            // == 从第一个中间件开始执行
            return dispatch(0);
        }
    }
}

// 测试
const app = new Application();

function delay() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve();
        }, 2000);
    });
}

app.use(async (ctx, next) => {
    ctx.body = '1';
    await next();
    ctx.body += '2';
});

app.use(async (ctx, next) => {
    ctx.body += '3';
    await delay();
    await next();
    ctx.body += '4';
});

app.use(async (ctx, next) => {
    ctx.body += '5';
});

app.listen(3000, () => {
    console.log('server running on port 3000');
});

koa2 源码阅读

地址: https://github.com/yunaichun/nodejs-study/tree/master/koa2-src

参考资料

powered by Gitbook该文件修订时间: 2023-05-16 18:08:03

results matching ""

    No results matching ""