koa包教包會系列(一) —— 白話koa

學習 koa 的必要性

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 主要作了兩件事情:

  1. 封裝 ctx
  2. 組裝中間件,實現逆序執行的洋蔥模型

總結

與 hapi,eggjs 比起來,koa 真的十分小巧,以致於不能稱做一種框架,能夠看作一種庫,但這並不妨礙 koa 生態的發展。

express 當初也是大而全的框架,慢慢的把各類功能已中間件的形式抽離出來,koa 能夠看作這種思想的一種實現。大而全的框架主要存在起初的學習成本高,功能冗餘等問題,使用 koa 對於初次使用 nodejs 開發 web 的人員很是友好,但也存在必定問題,過於靈活編程,致使編程方式千差萬別,沒有一個統一的標準,不一樣工程代碼之間學習成本高。

對於初學者來講,建議從 koa 入手,使用不一樣的中間件來實現不一樣的功能,對於瞭解 web 開發有很大幫助。當有必定積累和經驗後,能夠本身約定 koa 編程規則,當本身編程規則沒法知足需求時,就能夠入手真正的框架了。


關注微信公衆號:創宇前端(KnownsecFED),碼上獲取更多優質乾貨!

相關文章
相關標籤/搜索