Awesome.
Thanks bunches for this. π
This post is for plugin developers creating hooks to change functionality of NodeBB.
NodeBB supported a hook system since the early days of it's development. This system was built long before async/await was part of nodejs. Because of this the plugin system was built using a callback system.
When core fired a hook it would pass it a callback, and the callback would be called with the result once all the plugins processed the parameters. Here is a sample from the callback system.
// core
plugins.hooks.fire('filter:topics.get', { topics: topics }, function (err, result) {
console.log(results.topics);
//...
});
// your plugin
myPlugin.filterTopicsGet = function (hookData, callback) {
// do something async with topics and call callback
somethingAsync(hookData, function (err) {
callback(err, hookData);
});
}
Once promises and async/await support was widely available we switched core to use async/await. Now the same hook is fired as follows.
// core
const result = await plugins.hooks.fire('filter:topics.get', { topics: topics });
console.log(results.topics);
For backwards compatibility plugin hooks written with callback style still work, but you can use async functions in your plugins as well. The above sample would look like this
myPlugin.filterTopicsGet = async function (hookData) {
// do something async with topics
await somethingAsync(hookData);
return hookData;
}
Starting with 1.17.0, you can also use synchronous functions if your hook isn't making any async calls. Below are 3 different ways to write hooks, they are all supported.
// async (prefered style for async functions)
myPlugin.myHook = async function (hookData) {
// do some async call
await somethingAsync(hookData);
return hookData;
};
// callback-style (old style)
myPlugin.myHook = function (hookData, callback) {
// do some async call
somethingAsync(hookData, function (err) {
callback(err, hookData);
});
}
// sync function (new since 1.17.0)
myPlugin.myHook = function (hookData) {
// set some value on hookData
hookData.foo = 1;
return hookData;
}
You should not mix these styles together. For example do not return a value from the hook and call the callback at the same time.
myPlugin.badHook1 = function (hookData, callback) {
hookData.foo = 1;
callback(null, hookData);
return hookData;
};
// or
myPlugin.badHook2 = function (hookData, callback) {
hookData.foo = 1;
return setImmediate(callback, null, hookData);
};
Let us know if you have any questions.
Hello!
Can you explain the new standards for client-side hooks?
Previously we used the $(window).on(..., ...)
notation, and now we have the new hooks
module that we can use in our "client" code (was added in 1.17.0).
For example
require(['hooks'], function (hooks) {
hooks.on('action:ajaxify.end', ({ tpl_url }) => {
...
});
});
What the difference between these two ways and what should we use in our plugins?