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框架的理解,但願對你有幫助。若是上述內容有錯誤的地方,歡迎你們指正,謝謝~異步