最近在一次面試中被問到 koa 裏面的 delegates、request、respone、req、res之間的關係?我當時只回答了 koa-compose遞歸原理,雖然最後經過了面試,可是我以爲仍是有必要追其緣由,由於我沒回答出來。面試
createContext(req, res) {
const context = Object.create(this.context);
const request = context.request = Object.create(this.request);
const response = context.response = Object.create(this.response);
context.app = request.app = response.app = this;
context.req = request.req = response.req = req;
context.res = request.res = response.res = res;
request.ctx = response.ctx = context;
request.response = response;
response.request = request;
context.originalUrl = request.originalUrl = req.url;
context.state = {};
return context;
}
複製代碼
首先咱們必須先了解一下代碼npm
this.context = Object.create(context);
this.request = Object.create(request);
this.response = Object.create(response);
複製代碼
contextbash
const context = require('./context');
this.context = Object.create(context);
複製代碼
1.1. context 幹了什麼?app
const delegate = require('delegates');
const proto = module.exports = {
...
}
delegate(proto, 'response')
.method('attachment')
.method('redirect')..
delegate(proto, 'request')
.method('acceptsLanguages')
.method('acceptsEncodings')...
複製代碼
1.2. delegates幹了什麼?koa
module.exports = Delegator;
function Delegator(proto, target) {}
Delegator.auto = function(proto, targetProto, targetProp){}
Delegator.prototype.method = function(name){
proto[name] = function(){
return this[target][name].apply(this[target], arguments);
};
return this;
}
Delegator.prototype.access = function(name){
return this.getter(name).setter(name);
};
Delegator.prototype.getter = function(name){
proto.__defineGetter__(name, function(){
return this[target][name];
});
return this;
}
Delegator.prototype.setter = function(name){
proto.__defineSetter__(name, function(val){
return this[target][name] = val;
});
return this;
};
複製代碼
經常使用的 method 方法內部實現:async
proto[name] = function(){
return this[target][name].apply(this[target], arguments);
};
複製代碼
其實就是給context.js 返回的對象proto 對於request 、response 屬性增長增、讀取、設置、改變一些方法,每一個方法:函數
```
module.exports ={
...
}
request.js 封裝了req ,response.js封裝了res
```
複製代碼
const context = Object.create(this.context);
const request = context.request = Object.create(this.request);
const response = context.response = Object.create(this.response);
複製代碼
先建立context對象、而後爲context上下文增長request、request屬性。如今context除了context.js文件導出的proto對象的方法和屬性外、以及利用delegates在proto.request、proto.response上面定義的方法外,如今又在context.request、context.respons上面增長了分別對應request.js 和 response.js 默認導出的方法,request.js 又封裝了req ,response.js封裝了res。ui
context.app = request.app = response.app = this;
context.req = request.req = response.req = req;
context.res = request.res = response.res = res;
複製代碼
request.ctx = response.ctx = context;
request.response = response;
response.request = request;
複製代碼
context.originalUrl = request.originalUrl = req.url;
context.state = {};
複製代碼
在context上下文中咱們能夠查看originalUrl、statethis
const Koa = require("koa");
const app = new Koa();
app.use(async ctx => {
ctx.body = 'Hello World';
});
app.listen(3000);
複製代碼
在koa 源碼createContext函數裏面console.log(context) 就能夠看出整個函數返回context是什麼了。url