purify()

Remove side effects of previous calls for a certain function with purify(). This, in a way, can make functions with side effects "pure functions".

Syntax

purify(callback);

Parameters

callback
A function (possibly async) to purify. It introduces a new monitored context of type "undo" for every call of the function, to run the callback in. Upon each call, the previous call is undone, leaving no trace of listeners, observers, or other Flow-based operations.

Return value

A function, the purified version of the callback that was passed. The arguments are passed on to the callback, and the return value is passed on back. Additionally, the this value is passed on to the callback as well. When using an async callback, make sure to use until() for awaited expressions.

Examples

Toast messages

Let's say we're in a situation where a user may click on a button, an we want to provide some feedback in the form of a toast message (such as a simple "Saved" message). Given that we need the toast message to be removed after a certain delay, a naive approach to this problem could be

const toast = document.querySelector('#toast'); const showToast = async () => { document.body.append(toast); await timeout(7000); toast.remove(); };

Here, we're using timeout() to create a 7-second delay. At first glance, this seems to work. However, when doing more thorough testing, we'll find a bug; if the user clicks once, then again after 6 seconds, then the toast message gets removed only one second after the second click. What should happen is that the timeout() restarts from the beginning, so that the toast message always takes 7 seconds to disappear after the last time the user clicked the button.

The solution is to cancel the previous timeout() call when the showToast() function is called again before the previous timeout has finished. The purify() function exists for this goal specifically:

const toast = document.querySelector('#toast'); const showToast = purify(async () => { document.body.append(toast); await until(timeout(7000)); toast.remove(); });

Note that we'll also want to add until() to the await expression, to make sure the monitored context can pick back up where it left off.

Now, when repeatedly calling the showToast() function, the timeout() calls are properly cleaned up, causing the message to always be removed with a 7 second delay after the function was called.

Usage notes

The effect() helper also cleans up monitored contexts of type "undo", but additionally tracks live variables. When nesting a purify() call inside an effect(), be aware that the monitored contexts do not nest. The outer effect() call is therefore unable to "see" any of the monitorables, including live variables, inside the purified function.

See also