Description
As part of the hapi v17 work, I removed every closure from the hot path. This provided significant performance improvements. All these closures came from handlers passed to node EventEmitters (specifically from req
and res
object). In order to do that, I had to hang my own property on the emitter object. For example:
const handler = function (err) {
this._context.log(err);
};
// Inside some prototype methods:
req._context= this;
req.on('error', handler);
This works and can be improved by using symbols, but it's still messy. It also means adding multiple context properties per handler because they might need different context data. Instead, I would like to be able to do something as simple as:
const handler = function (err, context) {
context.log(err);
};
// Inside some prototype methods:
req.on('error', handler, this);
The idea is to pass a third optional argument to on()
and then append that argument to the end of the emit arguments list. We already store listeners as objects with properties. When this feature is not used, it means two additional if
statements: once to check if a third argument was provided and another to check if one is present and needs to be appended. If no third argument is provided, these two extra if
statements should not have any noticeable impact on performance.
However, since 99% of the time, emitter handlers require the creation of a callback closure, this should make applications using it much faster overall. Potentially, this can be used internally by node as well.
There is already a pattern for this in setTimeout()
. Most new JS features with callbacks now accept some kind of extra binding argument. Because we already bind the handler to the emitter, we cannot use this pattern.
I'm happy to do the work if the idea is acceptable.