koa 是由 express 原班人馬打造的,小巧的,健壯的 web 開發框架,也正由於它這些的優勢,eggjs 等不少 web 框架的核心也是由 koa 驅動的,熟悉 koa 代碼,不只對於使用 koa 進行開發有很大幫助,也有助於深刻理解像 eggjs 等這樣的,功能更增強大的框架。javascript
prototype 能夠說是整個 javascript 的核心,是深刻理解 javascript 關鍵知識點之一。
delegate 是一種編程方式,能夠簡化咱們的操做。前端
1.1 首先聲明「父類」(或子類的原型)java
const Car = {
get name() {
return this.engine.name;
},
start: function() {
return `${this.engine.name} start`;
},
};
複製代碼
1.2 使用用父類建立子類(父類在子類的原型鏈上)node
const BMW = Object.create(Car);
複製代碼
1.3 動態的給子類添加屬性web
BMW.engine = {
name: 'v8',
};
複製代碼
1.5 調用子類的方法express
BMW.name; // 'v8'
BMW.start(); // 'v8 start'
複製代碼
1.6 定義代理對象編程
const BMWPHONE = {};
複製代碼
1.7 定義代理方法api
function Delegate(source, target) {
this.source = source;
this.target = target;
}
Delegate.prototype.method = function(name) {
const target = this.target;
const source = this.source;
source[name] = function() {
return this[target][name].apply(this[target], arguments);
};
};
複製代碼
1.8 在代理對象上執行目標方法bash
const delegate = new Delegate(BMWPHONE, 'BMW');
delegate.method('start');
BMWPHONE.BMW = BMW;
BMWPHONE.start();
複製代碼
定義了 Car 父類,BMW 繼承了 Car 方法,並給 BMW 安裝了牛逼的引擎,如今能夠經過 BMW 手動啓動了;
如今 BMW 開發一款手機,用手機操做代理手動啓動。微信
之因此舉上面的例子(這裏你會體會到 js 和靜態語言的巨大差別),是由於 koa 中 4 個文件中,有 3 個都是與原型和代理相關。
koa 很是小巧,總共就 4 個文件,每一個文件的功能也十分單一,文件名也清楚的反應了文件功能。
koa 的文件結構
├── application.js
├── context.js
├── request.js
└── response.js
複製代碼
request.js
主要針對 http 的 request 對象提供了改對象的大量的 get 方法,文件主要是用來獲取 request 對象屬性,參考 1.1。
response.js
主要針對 http 的 response 對象提供了該對象的大量 set 方法;該文件主要是用來設置 response 對象屬性,參考 1.1。
context.js
koa 引入了上下文對象的概念,即 ctx,這裏所謂的上下文對象其實是 request 和 response 兩個對象的並集,request 和 response 分別經過代理的形式,參考 1.8,將本身的方法委託給 ctx。那樣咱們就能夠用 ctx 同時操做兩個對象,來簡化操做。
application.js
該文件是整個 koa 的核心,簡單來講主要有兩大功能: 掛載真實請求到 ctx 下,封裝中間件的執行順序
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;
}
複製代碼
這裏 createContext 就是上小節 1.3 中的操做--繼承原型鏈上的方法,給原型鏈上的方法準備數據。
這裏作了不少冗餘的掛載(冗餘是爲了兼容 express 部分寫法),若是你只須要用 ctx,那麼其中部分掛載能夠省略。
module.exports = compose;
function compose(middleware) {
return function(context, next) {
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);
}
}
};
}
複製代碼
koa 中間件的特色是逆序執行,或者說是洋蔥模型。以上 compose 方法就是實現洋蔥模型的代碼,上面方法簡單來講就是: 將下箇中間件的方法體,替換上箇中間件的 next 參數。 compose 方法應該算是 koa 中最難理解的部分了。
app.use(async function1(ctx, next) {
console.log(1.1);
next();
console.log(1.2);
})
app.use(async function2(ctx, next) {
console.log(2.1);
next();
console.log(2.2);
})
複製代碼
通過 compose 函數處理後,實際執行代碼能夠看作:
(async function1(ctx) {
console.log(1.1);
// next 部分
(async function2(ctx) {
console.log(2.1);
...
console.log(2.2)
}
)(ctx)
conosle.log(1.2);
})(ctx)
複製代碼
那麼能夠看出洋蔥模型的特色: 先註冊的中間件,位於模型的最外側。
實際上 koa 主要作了兩件事情:
與 hapi,eggjs 比起來,koa 真的十分小巧,以致於不能稱做一種框架,能夠看作一種庫,但這並不妨礙 koa 生態的發展。
express 當初也是大而全的框架,慢慢的把各類功能已中間件的形式抽離出來,koa 能夠看作這種思想的一種實現。大而全的框架主要存在起初的學習成本高,功能冗餘等問題,使用 koa 對於初次使用 nodejs 開發 web 的人員很是友好,但也存在必定問題,過於靈活編程,致使編程方式千差萬別,沒有一個統一的標準,不一樣工程代碼之間學習成本高。
對於初學者來講,建議從 koa 入手,使用不一樣的中間件來實現不一樣的功能,對於瞭解 web 開發有很大幫助。當有必定積累和經驗後,能夠本身約定 koa 編程規則,當本身編程規則沒法知足需求時,就能夠入手真正的框架了。
關注微信公衆號:創宇前端(KnownsecFED),碼上獲取更多優質乾貨!