Koa 和 express 区别
图层初始化的模式
express:采用嵌套模式,首先会创建框架中间件的 layer,也就是 app.use 和 router.use,再在中间件 layer 中创建路由的 layer,也就是 app.[httpMethods]、app.all、router.[httpMethods]、router.all。执行的顺序也就是先执行中间件 layer,再递归执行中间件中的 layer
((req, res) => {
console.log('I am the first middleware');
((req, res) => {
console.log('I am the second middleware');
(async(req, res) => {
console.log('I am the router middleware => /api/test1');
await sleep(2000)
res.status(200).send('hello')
})(req, res)
console.log('second middleware end calling');
})(req, res)
console.log('first middleware end calling')
})(req, res)
koa: 采用 promise 形式,不像 express 有两个 layer 层,koa 只有一个,用一个 middleWare 数组维护中间件,中间件执行顺序是采用洋葱模型,通过 middleMare 下标判断当前中间件是哪个,当执行 next 时,通过下标+1 递归执行 middleWare 的下一个中间件,如果出现异常则之后的中间件会被终止,直接 reject 出错误。然后再进行 handleRequest
通过 delegate
对路由事件进行委托,委托自定义的 request
, response
。 request
和 response
又对 node 原生的 req 和 res 进行方法代理,自定义了方法。
// middleWare 收集处理
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)
}
}
}
// 先收集 middleware,再执行路由拦截,执行方法
callback() {
const fn = compose(this.middleware);
if (!this.listenerCount('error')) this.on('error', this.onerror);
const handleRequest = (req, res) => {
const ctx = this.createContext(req, res);
return this.handleRequest(ctx, fn);
};
return handleRequest;
}
koa 还会对使用了 * yield 函数进行特殊处理,也就是 koa.convert。将 generator 函数 yield 的 value 转换成 promise 方法,这样就能一直 next 下去。通过 co 函数进行转换。
function co(gen) {
var ctx = this;
var args = slice.call(arguments, 1);
return new Promise(function(resolve, reject) {
if (typeof gen === 'function') gen = gen.apply(ctx, args);
if (!gen || typeof gen.next !== 'function') return resolve(gen);
onFulfilled();
function onFulfilled(res) {
var ret;
try {
ret = gen.next(res);
} catch (e) {
return reject(e);
}
next(ret);
return null;
}
function onRejected(err) {
var ret;
try {
ret = gen.throw(err);
} catch (e) {
return reject(e);
}
next(ret);
}
function next(ret) {
if (ret.done) return resolve(ret.value);
var value = toPromise.call(ctx, ret.value);
if (value && isPromise(value)) return value.then(onFulfilled, onRejected);
return onRejected(new TypeError('You may only yield a function, promise, generator, array, or object, '
+ 'but the following object was passed: "' + String(ret.value) + '"'));
}
});
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
上一篇: JS 中的 this 指向问题
下一篇: 彻底找到 Tomcat 启动速度慢的元凶
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论