<!DOCTYPE html>
<html lang="en-us">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <title>µsignal version</title>
    <style></style>
  </head>
  <body>
    <script type="module">
      import {
        signal,
        computed,
        effect,
      } from 'https://unpkg.com/usignal@0.4.2/esm/index.js?module';

      const fmt = new Intl.NumberFormat([], { maximumFractionDigits: 0 });

      const GRAPH_DEPTH = 640;

      function makeGraph(sources, depth) {
        let nodes = 0;
        for (; depth > 0; depth -= 1) {
          const left = sources[0];
          const right = sources[sources.length - 1];
          const nextLevel = [computed(() => 2 * left.value)];
          for (
            let prev = sources[0], i = 1, current = sources[i];
            i < sources.length;
            prev = current, i += 1, current = sources[i]
          ) {
            nextLevel[i] = computed(() => prev.value + current.value);
          }
          nextLevel[sources.length] = computed(() => 3 * right.value);
          nodes += nextLevel.length;
          sources = nextLevel;
        }
        console.log(`Created ${nodes} nodes.`);
        return sources;
      }

      function setup() {
        // create root signal
        const source = signal(1);
        const memos = makeGraph([source], GRAPH_DEPTH);

        // consume top row of memos
        let t0 = performance.now();
        effect(() => {
          const sum = memos.reduce((acc, memo) => acc + memo.value, 0);
          const interval = performance.now() - t0;
          console.log(`${fmt.format(interval)} ms; sum: ${sum}`);
        });

        return (newValue) => {
          t0 = performance.now();
          source.value = newValue;
        };
      }

      (function run(fn, value) {
        if (typeof fn === 'function' && typeof value === 'number') {
          fn(value); // e.g. update(2)
          return;
        }

        const update = setup();
        setTimeout(run, 0, update, 2);
      })();
    </script>
  </body>
</html>