node框架---koa 洋葱模型

洋葱模型

它能接受一个函数数组,然后返回一个新的函数,
函数自外向内,然后自内向外执行,和洋葱一样
例如:

const fn1 = (next) => {
    console.log(1);
    next();
    console.log(2);
};

const fn2 = (next) => {
    console.log(3);
    next();
    console.log(4);
};

const fn3 = (next) => {
    console.log(5);
    next();
    console.log(6);
};

const middlewares = [fn1, fn2, fn3];

compose(middlewares)();   //输出 1,3,5,6,4,2

实现compose,因为考虑到函数自外向内,然后自内向外执行,所以可以试下递归

function compose (composeList) {
	return function () {
	    next(0);
		async function next(i) {
			if (i === composeList.length) {
				return;
			}
			composeList[i](() => {
				awaite next(i+1);
			});
		}
	}
}

koa框架基本步骤

封装http server

class Application {
	constructor() {
        this.middlewares = [];
        this.context = context;
        this.request = request;
        this.response = response;
    }

	/**
     * 开启http server并传入callback
     */
    listen(...args) {
        let server = http.createServer(this.callback());
        server.listen(...args);
    }

	/**
     * 挂载回调函数
     * @param {Function} fn 回调处理函数
     */
    use(fn) {
        this.middlewares.push(middleware);
    }
    //原生的
	/* let server = http.createServer((req, res) => {
	    res.writeHead(200);
	    res.end('hello world');
	});
	server.listen(3000, () => {
	    console.log('listenning on 3000');
	});*/
	
	
}

封装request, response, context对象

处理url 以及 设置取值 body、status 以及给 context对象赋值

中间机制处理-----洋葱

/**
        * 中间件合并方法,将中间件数组合并为一个中间件
        * @return {Function}
        */
    compose() {
        // 将middlewares合并为一个函数,该函数接收一个ctx对象
        return async ctx => {

            function createNext(middleware, oldNext) {
                return async () => {
                    await middleware(ctx, oldNext);
                };
            }

            let len = this.middlewares.length;
            let next = async () => {
                return Promise.resolve();
            };
            for (let i = len - 1; i >= 0; i--) {
                let currentMiddleware = this.middlewares[i];
                next = createNext(currentMiddleware, next);
            }

            await next();
        };
    }


    /**
     * 获取http server所需的callback函数
     * @return {Function} fn
     */
    callback() {
        return (req, res) => {
            let ctx = this.createContext(req, res);
            let respond = () => this.responseBody(ctx);
            let one rror = (err) => this.onerror(err, ctx);
            let fn = this.compose();
            // 在这里catch异常,调用onerror方法处理异常
            return fn(ctx).then(respond).catch(onerror);
        };
    }

    /**
     * 构造ctx
     * @param {Object} req node req实例
     * @param {Object} res node res实例
     * @return {Object} ctx实例
     */
    createContext(req, res) {
        // 针对每个请求,都要创建ctx对象
        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;
    }

错误处理

在回调函数中callback catch捕捉错误

/**
     * 错误处理
     * @param {Object} err Error对象
     * @param {Object} ctx ctx实例
     */
    one rror(err, ctx) {
        if (err.code === 'ENOENT') {
            ctx.status = 404;
        }
        else {
            ctx.status = 500;
        }
        let msg = err.message || 'Internal error';
        ctx.res.end(msg);
        // 触发error事件
        this.emit('error', err);
    }
上一篇:NodeJS-模块化


下一篇:前端工程 常见问题随笔记录