Egg 框架擴(kuò)展

2020-02-06 14:11 更新

框架提供了多種擴(kuò)展點(diǎn)擴(kuò)展自身的功能:

  • Application
  • Context
  • Request
  • Response
  • Helper

在開(kāi)發(fā)中,我們既可以使用已有的擴(kuò)展 API 來(lái)方便開(kāi)發(fā),也可以對(duì)以上對(duì)象進(jìn)行自定義擴(kuò)展,進(jìn)一步加強(qiáng)框架的功能。

Application

app 對(duì)象指的是 Koa 的全局應(yīng)用對(duì)象,全局只有一個(gè),在應(yīng)用啟動(dòng)時(shí)被創(chuàng)建。

訪問(wèn)方式

  • ctx.app
  • Controller,Middleware,Helper,Service 中都可以通過(guò) this.app 訪問(wèn)到 Application 對(duì)象,例如 this.app.config 訪問(wèn)配置對(duì)象。
  • 在 app.js 中 app 對(duì)象會(huì)作為第一個(gè)參數(shù)注入到入口函數(shù)中// app.jsmodule.exports = app => { // 使用 app 對(duì)象};

擴(kuò)展方式

框架會(huì)把 app/extend/application.js 中定義的對(duì)象與 Koa Application 的 prototype 對(duì)象進(jìn)行合并,在應(yīng)用啟動(dòng)時(shí)會(huì)基于擴(kuò)展后的 prototype 生成 app 對(duì)象。

方法擴(kuò)展

例如,我們要增加一個(gè) app.foo() 方法:

// app/extend/application.js
module.exports = {
foo(param) {
// this 就是 app 對(duì)象,在其中可以調(diào)用 app 上的其他方法,或訪問(wèn)屬性
},
};

屬性擴(kuò)展

一般來(lái)說(shuō)屬性的計(jì)算只需要進(jìn)行一次,那么一定要實(shí)現(xiàn)緩存,否則在多次訪問(wèn)屬性時(shí)會(huì)計(jì)算多次,這樣會(huì)降低應(yīng)用性能。

推薦的方式是使用 Symbol + Getter 的模式。

例如,增加一個(gè) app.bar 屬性 Getter:

// app/extend/application.js
const BAR = Symbol('Application#bar');

module.exports = {
get bar() {
// this 就是 app 對(duì)象,在其中可以調(diào)用 app 上的其他方法,或訪問(wèn)屬性
if (!this[BAR]) {
// 實(shí)際情況肯定更復(fù)雜
this[BAR] = this.config.xx + this.config.yy;
}
return this[BAR];
},
};

Context

Context 指的是 Koa 的請(qǐng)求上下文,這是 請(qǐng)求級(jí)別 的對(duì)象,每次請(qǐng)求生成一個(gè) Context 實(shí)例,通常我們也簡(jiǎn)寫(xiě)成 ctx。在所有的文檔中,Context 和 ctx 都是指 Koa 的上下文對(duì)象。

訪問(wèn)方式

  • middleware 中 this 就是 ctx,例如 this.cookies.get('foo')。
  • controller 有兩種寫(xiě)法,類的寫(xiě)法通過(guò) this.ctx,方法的寫(xiě)法直接通過(guò) ctx 入?yún)ⅰ?/li>
  • helper,service 中的 this 指向 helper,service 對(duì)象本身,使用 this.ctx 訪問(wèn) context 對(duì)象,例如 this.ctx.cookies.get('foo')。

擴(kuò)展方式

框架會(huì)把 app/extend/context.js 中定義的對(duì)象與 Koa Context 的 prototype 對(duì)象進(jìn)行合并,在處理請(qǐng)求時(shí)會(huì)基于擴(kuò)展后的 prototype 生成 ctx 對(duì)象。

方法擴(kuò)展

例如,我們要增加一個(gè) ctx.foo() 方法:

// app/extend/context.js
module.exports = {
foo(param) {
// this 就是 ctx 對(duì)象,在其中可以調(diào)用 ctx 上的其他方法,或訪問(wèn)屬性
},
};

屬性擴(kuò)展

一般來(lái)說(shuō)屬性的計(jì)算在同一次請(qǐng)求中只需要進(jìn)行一次,那么一定要實(shí)現(xiàn)緩存,否則在同一次請(qǐng)求中多次訪問(wèn)屬性時(shí)會(huì)計(jì)算多次,這樣會(huì)降低應(yīng)用性能。

推薦的方式是使用 Symbol + Getter 的模式。

例如,增加一個(gè) ctx.bar 屬性 Getter:

// app/extend/context.js
const BAR = Symbol('Context#bar');

module.exports = {
get bar() {
// this 就是 ctx 對(duì)象,在其中可以調(diào)用 ctx 上的其他方法,或訪問(wèn)屬性
if (!this[BAR]) {
// 例如,從 header 中獲取,實(shí)際情況肯定更復(fù)雜
this[BAR] = this.get('x-bar');
}
return this[BAR];
},
};

Request

Request 對(duì)象和 Koa 的 Request 對(duì)象相同,是 請(qǐng)求級(jí)別 的對(duì)象,它提供了大量請(qǐng)求相關(guān)的屬性和方法供使用。

訪問(wèn)方式

ctx.request

ctx 上的很多屬性和方法都被代理到 request 對(duì)象上,對(duì)于這些屬性和方法使用 ctx 和使用 request 去訪問(wèn)它們是等價(jià)的,例如 ctx.url === ctx.request.url。

Koa 內(nèi)置的代理 request 的屬性和方法列表:Koa - Request aliases

擴(kuò)展方式

框架會(huì)把 app/extend/request.js 中定義的對(duì)象與內(nèi)置 request 的 prototype 對(duì)象進(jìn)行合并,在處理請(qǐng)求時(shí)會(huì)基于擴(kuò)展后的 prototype 生成 request 對(duì)象。

例如,增加一個(gè) request.foo 屬性 Getter:

// app/extend/request.js
module.exports = {
get foo() {
return this.get('x-request-foo');
},
};

Response

Response 對(duì)象和 Koa 的 Response 對(duì)象相同,是 請(qǐng)求級(jí)別 的對(duì)象,它提供了大量響應(yīng)相關(guān)的屬性和方法供使用。

訪問(wèn)方式

ctx.response

ctx 上的很多屬性和方法都被代理到 response 對(duì)象上,對(duì)于這些屬性和方法使用 ctx 和使用 response 去訪問(wèn)它們是等價(jià)的,例如 ctx.status = 404 和 ctx.response.status = 404 是等價(jià)的。

Koa 內(nèi)置的代理 response 的屬性和方法列表:Koa Response aliases

擴(kuò)展方式

框架會(huì)把 app/extend/response.js 中定義的對(duì)象與內(nèi)置 response 的 prototype 對(duì)象進(jìn)行合并,在處理請(qǐng)求時(shí)會(huì)基于擴(kuò)展后的 prototype 生成 response 對(duì)象。

例如,增加一個(gè) response.foo 屬性 setter:

// app/extend/response.js
module.exports = {
set foo(value) {
this.set('x-response-foo', value);
},
};

就可以這樣使用啦:this.response.foo = 'bar';

Helper

Helper 函數(shù)用來(lái)提供一些實(shí)用的 utility 函數(shù)。

它的作用在于我們可以將一些常用的動(dòng)作抽離在 helper.js 里面成為一個(gè)獨(dú)立的函數(shù),這樣可以用 JavaScript 來(lái)寫(xiě)復(fù)雜的邏輯,避免邏輯分散各處。另外還有一個(gè)好處是 Helper 這樣一個(gè)簡(jiǎn)單的函數(shù),可以讓我們更容易編寫(xiě)測(cè)試用例。

框架內(nèi)置了一些常用的 Helper 函數(shù)。我們也可以編寫(xiě)自定義的 Helper 函數(shù)。

訪問(wèn)方式

通過(guò) ctx.helper 訪問(wèn)到 helper 對(duì)象,例如:

// 假設(shè)在 app/router.js 中定義了 home router
app.get('home', '/', 'home.index');

// 使用 helper 計(jì)算指定 url path
ctx.helper.pathFor('home', { by: 'recent', limit: 20 })
// => /?by=recent&limit=20

擴(kuò)展方式

框架會(huì)把 app/extend/helper.js 中定義的對(duì)象與內(nèi)置 helper 的 prototype 對(duì)象進(jìn)行合并,在處理請(qǐng)求時(shí)會(huì)基于擴(kuò)展后的 prototype 生成 helper 對(duì)象。

例如,增加一個(gè) helper.foo() 方法:

// app/extend/helper.js
module.exports = {
foo(param) {
// this 是 helper 對(duì)象,在其中可以調(diào)用其他 helper 方法
// this.ctx => context 對(duì)象
// this.app => application 對(duì)象
},
};

按照環(huán)境進(jìn)行擴(kuò)展

另外,還可以根據(jù)環(huán)境進(jìn)行有選擇的擴(kuò)展,例如,只在 unittest 環(huán)境中提供 mockXX() 方法以便進(jìn)行 mock 方便測(cè)試。

// app/extend/application.unittest.js
module.exports = {
mockXX(k, v) {
}
};

這個(gè)文件只會(huì)在 unittest 環(huán)境加載。

同理,對(duì)于 Application,Context,Request,Response,Helper 都可以使用這種方式針對(duì)某個(gè)環(huán)境進(jìn)行擴(kuò)展,更多參見(jiàn)運(yùn)行環(huán)境。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)