Skip to content

A simple utility that limits the impact of functions the demand high CPU load

License

Notifications You must be signed in to change notification settings

devonChurch/eggs-benedict

Repository files navigation

Eggs Benedict 🥚🥓🍞🍽

What 👋

A simple utility that limits the impact of functions the demand high CPU load.

Why 🤷‍♀️

Functionality that demands intense CPU load can create a poor user experience as their session can hang and become unresponsive.

There are throttle and debounce solutions that help to alleviate the repercussions of CPU intensive UI. Eggs Benedict incorporates these methodologies into a lightweight React and Vanilla JS abstraction.


Eggs Benedict was originally designed to help with the various complex calculations associated with the Avocado application. The library has since been enhanced into a simple developer API that can yield powerful results.

Avocado demo

How 💡

This library uses Request Animation Frame to implement throttle and debounce solutions simultaneously. This provides the real-time updates of a throttler while ensuring that the UI does not fall out of sync with a debouncer.

Eggs Benedict Flow

Options ⚙️

Eggs Benedict offers some light configuration for custom throttle and debounce delays.

{
  throttleDelay: 0, // Default.
  debounceDelay: 100 // Default.
}

Take a look at the interactive CodeSandbox to see configuration examples and their correlation with different CPU loads.

eggs-benedict-options-example

Typescript 👌

You can reference the Eggs Benedict types directly in your application.

import { Options } from "eggs-benedict/types";

You can also supply a typed callback as a generic to the React Hooks and Vanilla JS initializers.

React Hooks

// prettier-ignore
const setLoadControlValue =
  useLoadControl<(value: string) => void>(callback);

Vanilla JS

// prettier-ignore
const [activeLoadControl, cleanUpLoadControl] =
  LoadControl<(value: string) => void>(callback);

Examples 📝

React Hooks

In this example we are using the React Hooks import to run some CPU heavy work when the Range <input /> changes its value.

import React from "react";
import { useLoadControl } from "eggs-benedict/hooks";

export default function App() {
  const [count, setCount] = React.useState(0);
  const heavyCpuLoad = (value) => {
    /**
     * CPU HEAVY WORK HERE!
     * - - - - - - - - - - -
     * Maybe some complex calculations based on the Range <input /> value 🤓
     */
    setCount(value);
  };
  const setLoadControlCount = useLoadControl(heavyCpuLoad);
  const handleChange = (event) =>
    setLoadControlCount(event.currentTarget.value);

  return (
    <>
      <input type="range" value={count} onChange={handleChange} />
      <p>{count}</p>
    </>
  );
}

Vanilla JS

In this example we are using a Vanilla JS implementation inside a React useEffect scaffold. When the user scrolls the window we run a CPU heavy callback.

import React from "react";
import LoadControl from "eggs-benedict";

export default function App() {
  const [scroll, setScroll] = React.useState(0);
  React.useEffect(() => {
    const heavyCpuLoad = (event) => {
      /**
       * CPU HEAVY WORK HERE!
       * - - - - - - - - - - -
       * Maybe slow DOM heavy math to move some elements around 🤓
       */
      setScroll(event.currentTarget.scrollY);
    };
    const [scrollLoadControl, cleanUpScrollLoadControl] = LoadControl(
      heavyCpuLoad
    );
    window.addEventListener("scroll", scrollLoadControl);

    /**
     * Remember to remove the Eggs Benedict instance when unmounting your
     * <Component /> 👍
     */
    return cleanUpScrollLoadControl;
  }, []);
  return (
    <>
      <p style={{ position: "fixed" }}>{scroll}</p>
      <div
        style={{
          height: "200vh",
          backgroundImage: "linear-gradient(to bottom, #58FFC7, #2D8165)",
        }}
      />
    </>
  );
}