hamo v1.0.0-dev.6
🎣 Hamo
Hāmo, from latin:
hooked. ZERO overhead hooks.
Synopsis
Hamo provides a handy interface for attaching before / after / once hooks to any function without zero overhead.
Fully compatible with both Node and the browser.
How it works
The hooked function is dynamically builded during runtime. Only the pieces relative to the currently active hooks are added to the hooked function body. When no hooks are attached to the hooked function, the original function is used.
To invoke the after hooks really after the hooked function has already returned,
a micro-task is scheduled by running the hooks inside an already resolved promise.
TOC
Installation
npm install hamo --saveIf not using a bundler:
<script src="https://unpkg.com/hamo"></script>Usage
The hamo function accepts 2 arguments:
1. function to be hooked.
2. async flag (specify if the provided function is async or not).
It returns an array of 3 elements:
1. hooked.
2. on, function used to attach hooks to hooked.
3. off, function used to detach hooks from hooked.
A suggested naming could be [function], on[function], off[function]:
const [func, on, off] = hamo(function, async);Getting started
Basic example of hooking a function. The sum function is exactly the function passed as argument to hamo.
const hamo = require('hamo');
const [sum] = hamo((a, b) => a + b);
sum(1, 2); // 3Possible hooks
The existent hooks are:
beforeoncebeforeafteronceafter
Define a hook
A hook can be defined passing to the on function two arguments:
1. Argument that define the timing of the hook (hookString).
2. Hook function (hookFunction).
on(hookString, hookFunction)const [sum, onSum] = hamo((a, b) => a + b);
onSum('before', () => console.log('Called before!'));
sum(1, 2);
// Called before
// 3Before and oncebefore
before and oncebefore hooks gets called before the function execution.
Those functions are feeded with the same set of arguments that is passed to the hooked function.
NOTE: oncebefore Is called only one time.
const [sum, onSum] = hamo((a, b) => a + b);
onSum('before', (a, b) => console.log(`Summing ${a} and ${b}`));
sum(1, 2);
// Summing 1 and 2
// 3After and onceafter
before and onceafter hooks gets called after the function execution.
Those functions are feeded with the result of the hooked function AND with the same set of arguments that is passed to the hooked function.
NOTE: onceafter Is called only one time.
NOTE1: These functions are invoked after the function has returned.
const [sum, onSum] = hamo((a, b) => a + b);
onSum('after', (res, a, b) => console.log(`Sum is equal to ${res}`));
sum(1, 2);
// 3
// Sum is equal to 3Multiple hooks
Multiple hooks of the same type can be defined. Every hook of the same type will be executed with the same set of argument.
const [sum, onSum] = hamo((a, b) => a + b);
onSum('before', () => console.log('Called before than the next before!'));
onSum('before', () => console.log('Called before than the func!'));
sum(1, 2);
// Called before than the next before
// Called before than the func
// 3Detach hook
A previously defned hook is detachable by invoking the off function with the hookString argument
off(hookString);NOTE: onceafter Is called only one time.
NOTE1: These functions are invoked after the function has returned.
const [sum, onSum, offSum] = hamo((a, b) => a + b);
onSum('after', (res, a, b) => console.log(`Sum is equal to ${res}`));
offSum('after');
sum(1, 2);
// 3Hooking async functions
It's possible to hook async functions.
const sleepFunc = ms => new Promise(resolve => setTimeout(resolve, ms));
// Specify the async flag
const [sleep, onSleep] = hamo(sleepFunc, true);
onSleep('after', (ms) => console.log(`Just slept for ${ms}ms`));
(async () => {
await sleep(1000);
})();
// ( sleeping )
// Just slept for 1000msReal World Examples
Hooking fs
Example of hooking fs.
const { readFile } = require('fs');
const { promisify } = require('util');
// Specify the async flag
const [read, onRead] = hamo(promisify(readFile), true);
onRead('after', (file, path) => console.log(`Finished reading from ${path}`));
read('./test.txt', 'utf-8');
// ... test.txt ...
// Finished reading from ./test.txtHooking React components
Example of hooking a React component and logging on different rendering stages.
const HelloComponent = ({ who }) => {
console.log('Rendering component');
return <h1>Hello {who}</h1>;
};
const [Hello, onHello] = hamo(HelloComponent);
onHello('before', ({ who }) => console.log(`Rendering hello component with prop ${who}`));
onHello('after', () => console.log('Rendered hello component'));
React.render(<Hello who="world" />, '#App');
// Rendering hello component with prop world
// Rendering component
// ( Now the component is rendered in the dom )
// Rendered hello componentBenchmarks
To run benchmarks:
- clone repo.
npm install- run files inside
/benchmarks.
Test
To run tests:
- clone repo
npm installnpm test
License
MIT