Introducing Hamo - Zero overhead hooks 🎣
Tags: javascript, react, node, showdev
Published: 2019-06-19 00:06:03

Hi 👋

Today I would like to introduce you to a tiny library I just finished.

It's called `Hamo` (Latin for `hook`) and will let you hook **literally** everything, adding **zero** overhead.

# The problem
Hooks are useful, but often they get in the way. You can implement them yourself with event emitters. But, any implementation would require quite a lot of effort and added complexity to your functions.

And more importantly, depending on how much critical is the function that needs to be hooked, a non negligible increase in overhead with a consequent slow down.

What if you could hook your functions, from everywhere in your app, without decreasing performance of a single ounce?

# The solution

With `Hamo` you can do things like the following.

```javascript
const hamo = require('hamo');

const [sum, onSum] = hamo((a, b) => a + b);

onSum('after', (result, a, b) => console.log(`The sum of ${a} plus ${b} is ${result}`);

sum(1, 3);

// 3
// The sum of 1 plus 2 is 3
```

Pretty handy right?

You can actually hook functions `before / after / oncebefore / onceafter` the hooked function.

Well, that wasn't a life changing example, let's some examples from the real world:

## Node

In the following snippet we are hooking a write function. 

```javascript
const hamo = require('hamo');
const { writeFile } = require('hamo');
const { promisify } = require('promisify');

// The `true` argument will notify hamo that the passed function is async
const [write, onWrite, offWrite] = hamo(promisify(writeFile), true);

module.exports = {
     write,
     onWrite,
     offWrite,
};
```

Then, from everywhere in your app, you can **attach** or **detach** hooks and be notified when something is written to disk.

Like a notification system for functions.

```javascript
onWrite('before', path => console.log(`Writing file to ${path}`);

// Writing file to {path} 
// ... somewhere `write` is busy writing something ...

offWrite('before');

// no more notifies 🌺
```

## Browser

Maybe you want to be notified when a `React` (functional) component renders.

```jsx
const HelloComp = () => <h1>Hello!</h1>;

const [Hello, onHello] => hamo(HelloComp);

onHello('before', () => console.log('Rendering Hello...'));

onHello('after', () => console.log('Rendered Hello 🎉'));

// then, when mounting..

const App = () => {
     console.log('Mounting App...');
     
     return <Hello />;
};

// Mounting App...
// Rendering Hello...
// Rendered Hello 🎉
```

# How it works?

## Zero overhead

The hooks that are attached to a function are detected. Then, the body of the resulting handler is dynamically generated during runtime. There are no `if` statements inside it, as only the pieces strictly needed for the currently active hooks are added to the function body.

So, zero hooks, zero overhead.

## Running functions after return statements

How is it possible to run functions from a function that has already returned?
This is achieved by scheduling a `micro-task` in the event-loop in the following way.

```javascript
const func = () => {
     Promise.resolve().then(() => console.log(42));
     return 'The answer is';
};

func();

// The answer is
// 42
``` 

By running code inside an already resolved promise, you are making sure that the event-loop will pick up the tasks and will schedule them for a little later.

Well, that's pretty much it.

You can check out the repo here:
https://github.com/lucagez/hamo

Happy hooks everyone! 🎣