context.js
-
context.js
里面放的就是用于新建上下文对象的原型代码。除了一个处理错误的onerror
方法以外,主要用了一个delegates
模块,进行属性和方法的绑定。
- 比如:
delegate(proto, 'response')
.method('attachment')
.method('redirect')
.method('remove')
.method('vary')
.method('set')
.method('append')
.method('flushHeaders')
.access('status')
.access('message')
.access('body')
.access('length')
.access('type')
.access('lastModified')
.access('etag')
.getter('headerSent')
.getter('writable');
- 上述的代码就是将
ctx.response
上面的方法和属性,代理绑定到ctx
上。比如:绑定完成后调用ctx.redirect
,其实就是在调用ctx.response.redirect
。
-
access
与getter
都是用来绑定属性,不过getter
绑定的数据是只读的,access
绑定的属性才是可读可写的。
Delegator
- 下面来看看Delegator里用于绑定属性和方法的源码
-
method
用于代理方法,proto
是ctx
的原型,target
对应的是ctx
上面的response
或request
。
Delegator.prototype.method = function(name){
var proto = this.proto;
var target = this.target;
this.methods.push(name);
proto[name] = function(){
return this[target][name].apply(this[target], arguments);
};
return this;
};
-
access
用于绑定可重写的属性、getter
定义只读属性
Delegator.prototype.access = function(name){
return this.getter(name).setter(name);
};
Delegator.prototype.setter = function(name){
var proto = this.proto;
var target = this.target;
this.setters.push(name);
proto.__defineSetter__(name, function(val){
return this[target][name] = val;
});
return this;
};
Delegator.prototype.getter = function(name){
var proto = this.proto;
var target = this.target;
this.getters.push(name);
proto.__defineGetter__(name, function(){
return this[target][name];
});
return this;
};
- 稍微总结一下,每个方法最后都会返回
this
,这样可以支持链式调用。
-
__defineGetter__
和__defineSetter__
并不是标准的API,不存在于ECMAScript中,并不推荐使用。可以用Object. defineProperty
实现同样的功能。
- 实现代理时,是将所有的属性和方法绑定到了
ctx
的原型上面去了。
koa-compose
- 这个模块就只封装了一个
compose
方法,用于组合排版koa的中间件。首先对middleware
和他的元素进行类型判断。然后返回一个递归执行的函数。
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!')
}
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)
}
}
}
}
- 从上面代码再结合上一篇代码中的
handleRequest
和fnMiddleware
方法,可以了解到koa中间件的机制(后面单独再写一篇吧)。