-
-
Notifications
You must be signed in to change notification settings - Fork 3.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
emit more events #1395
base: master
Are you sure you want to change the base?
emit more events #1395
Changes from 3 commits
83940d0
4c4d064
82b5f1c
2faaa63
7303f20
c719bdb
0fc13d9
e4bf680
2d181dd
7190d4e
6b996ba
31911c4
4107093
4d70048
3b47e65
1bdfebb
0681713
c3369bf
bc62b2a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -219,6 +219,64 @@ Note: | |
- Many properties on `ctx` are defined using getters, setters, and `Object.defineProperty()`. You can only edit these properties (not recommended) by using `Object.defineProperty()` on `app.context`. See https://github.com/koajs/koa/issues/652. | ||
- Mounted apps currently use their parent's `ctx` and settings. Thus, mounted apps are really just groups of middleware. | ||
|
||
## Events | ||
|
||
Koa application is an instance of `EventEmitter` and emits following events to allow hooks into lifecycle. | ||
All these events (except `error`) have `ctx` as first parameter: | ||
|
||
### Event: 'request' | ||
|
||
Emitted each time there is a request, with `ctx` as parameter, before passing to any middleware. | ||
May be a good place for per-request context mutation, when needed, for example: | ||
|
||
```js | ||
app.on('request', ctx => { | ||
ctx.state.start = Date.now(); | ||
// or something more advanced | ||
if(!ctx.get('DNT')) ctx.state = new Proxy({}) | ||
}) | ||
``` | ||
|
||
### Event: 'respond' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i don't see how this or the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it actually has less benefit because you cannot use async functions There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is no need to have advantage or disadvantage and not always sync call is inferior to async call from application point of view. If you follow Node.JS core development strategy then you certainly will notice “mix and match” innovation in handling async flow - |
||
|
||
Emitted after passing all middleware, but before sending the response to network. | ||
May be used when some action required to be latest after all middleware processing, for example: | ||
|
||
```js | ||
app.on('respond', ctx => { | ||
if (ctx.state.start) ctx.set('X-Response-Time', Date.now() - ctx.state.start) | ||
}) | ||
``` | ||
|
||
### Event: 'responded' | ||
|
||
Emitted when the response stream is finished. Good place to cleanup any resources attached to `ctx.state` for example: | ||
|
||
```js | ||
app.on('responded', ctx => { | ||
if (ctx.state.dataStream) ctx.state.dataStream.destroy(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i don't understand this use-case. clean up callbacks on streams should be handled when you create and pipe them. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How would you know from the stream that, for example, connection with a client was prematurely lost and not the whole stream was consumed? |
||
}) | ||
``` | ||
|
||
More advanced example, use events to detect that server is idling for some time: | ||
tinovyatkin marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
```js | ||
const onIdle10000ms = () => { console.warn('Server is idle for 10 seconds!'); } | ||
const IDLE_INTERVAL = 10000; | ||
let idleInterval = setInterval(onIdle10000ms, IDLE_INTERVAL); | ||
app | ||
.on('request', () => { | ||
clearInterval(idleInterval); | ||
}) | ||
.on('responded', () => { | ||
idleInterval = setInterval(onIdle10000ms, IDLE_INTERVAL); | ||
}) | ||
``` | ||
|
||
### Event: 'error' | ||
|
||
See **Error Handling** below. | ||
|
||
## Error Handling | ||
|
||
By default outputs all errors to stderr unless `app.silent` is `true`. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -157,8 +157,15 @@ module.exports = class Application extends Emitter { | |
handleRequest(ctx, fnMiddleware) { | ||
const res = ctx.res; | ||
res.statusCode = 404; | ||
const onerror = err => ctx.onerror(err); | ||
const handleResponse = () => respond(ctx); | ||
const onerror = err => { | ||
if (null != err) ctx.onerror(err); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is breaking change. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What does it breaks?! |
||
this.emit('responded', ctx); | ||
}; | ||
const handleResponse = () => { | ||
this.emit('respond', ctx); | ||
respond(ctx); | ||
}; | ||
this.emit('request', ctx); | ||
onFinished(res, onerror); | ||
return fnMiddleware(ctx).then(handleResponse).catch(onerror); | ||
} | ||
|
@@ -218,6 +225,8 @@ function respond(ctx) { | |
let body = ctx.body; | ||
const code = ctx.status; | ||
|
||
ctx.app.emit('respond', ctx); | ||
tinovyatkin marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// ignore body | ||
if (statuses.empty[code]) { | ||
// strip headers | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks for this doc, very useful for a PR