Express和Koa都是基于Nodejs平台的web框架,也是目前比较常见的用于快速开发web服务的框架,且二者都是基于middleware的方式去处理客户端请求,那么二者有何区别呢?
简单点说就是,“Express是直线型,Koa是洋葱模型”。(喊口号!!!)
咱们先来看看下面的示例代码:web
// for express example const express = require('express'); const app = express(); function cb1(req, res, next) { console.log('>>>>>>cb1'); next(); console.log('<<<<<<cb1'); } function cb2(req, res, next) { console.log('>>>cb2<<<'); res.send('hello world'); } app.use('/', [cb1, cb2]); app.listen(3000);
// for koa2 example const koa = require('koa2'); const app = koa(); function cb1(ctx, next) { console.log('>>>>>>cb1'); next(); console.log('<<<<<<cb1'); } function cb2(ctx, next) { console.log('>>>cb2<<<'); ctx.body = 'hello world'; } app.use(cb1); app.use(cb2); app.listen(3000);
以上两段代码的输出皆为:express
>>>>>>cb1 >>>cb2<<< <<<<<<cb1
因此,当middleware为同步函数时,二者从执行结果上来看并没有区别。
咱们再来看看下面的示例代码:api
// for express example const express = require('express'); const app = express(); async function cb1(req, res, next) { console.log('>>>>>>cb1'); await next(); console.log('<<<<<<cb1'); } async function cb2(req, res, next) { return new Promise((resolve) => { setTimeout(resolve, 500); }).then(() => { console.log('>>>cb2<<<'); res.send('hello world'); }); } app.use('/', [cb1, cb2]); app.listen(3000);
// for koa2 example const koa = require('koa2'); const app = new koa(); async function cb1(ctx, next) { console.log('>>>>>>cb1'); await next(); console.log('<<<<<<cb1'); } async function cb2(ctx, next) { return new Promise((resolve) => { setTimeout(resolve, 500); }).then(() => { console.log('>>>cb2<<<'); ctx.body = 'hello world'; }); } app.use(cb1); app.use(cb2); app.listen(3000);
express-example的输出为:promise
>>>>>>cb1 >>>>>>cb1 >>>cb2>>>
而koa2-example的输出为:app
>>>>>>cb1 >>>cb2<<< <<<<<<cb1
从上面的例子能够看出,当middleware为异步函数时,Express和Koa的执行流程是不一样的。Express的返回结果并非咱们设想中的结果,是什么缘由致使的行为差别呢?下面,让咱们一块儿来简单的分析下Express和Koa中执行middleware部分的源码片断。
在Express中,执行middleware的逻辑代码主要位于lib/router/route.js和lib/router.layer.js文件:框架
// route.js Route.prototype.dispatch = function dispatch(req, res, done) { var idx = 0; var stack = this.stack; if (stack.length === 0) { return done(); } var method = req.method.toLowerCase(); if (method === 'head' && !this.methods['head']) { method = 'get'; } req.route = this; next(); function next(err) { // signal to exit route if (err && err === 'route') { return done(); } // signal to exit router if (err && err === 'router') { return done(err) } var layer = stack[idx++]; if (!layer) { return done(err); } if (layer.method && layer.method !== method) { return next(err); } if (err) { layer.handle_error(err, req, res, next); } else { layer.handle_request(req, res, next); } } }; //layer.js Layer.prototype.handle_error = function handle_error(error, req, res, next) { var fn = this.handle; if (fn.length !== 4) { // not a standard error handler return next(error); } try { fn(error, req, res, next); } catch (err) { next(err); } }; Layer.prototype.handle_request = function handle(req, res, next) { var fn = this.handle; if (fn.length > 3) { // not a standard request handler return next(); } try { fn(req, res, next); } catch (err) { next(err); } };
在Koa2中,执行middleware的逻辑代码主要位于koa-compose/index.js文件:koa
function 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!') } /** * @param {Object} context * @return {Promise} * @api public */ return function (context, next) { // last called middleware # 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 { return Promise.resolve(fn(context, function next () { return dispatch(i + 1) })) } catch (err) { return Promise.reject(err) } } } }
由上可知,Express中middleware的next参数是一个普通的函数对象,而Koa中middleware的next参数是一个promise对象。因此当咱们挂载异步的middleware时,Express并不能像Koa同样,在middleware中使用await去等待下一个middleware执行完成以后,再执行当前middleware的后续逻辑。这就是为何“Express是直线型,Koa是洋葱模型”的根本缘由。
以上就是我对于Express和Koa框架的理解,但愿对你有帮助。若是上述内容有错误的地方,欢迎你们指正,谢谢~异步