1 | <div align="right">
|
2 | <h1><code>tabling</code></h1>
|
3 | <br />
|
4 | <br />
|
5 |
|
6 | <p><code>npm add tabling</code> makes objects lazy</p>
|
7 | <span>
|
8 | <a href="https://github.com/maraisr/tabling/actions/workflows/ci.yml">
|
9 | <img src="https://github.com/maraisr/tabling/actions/workflows/ci.yml/badge.svg"/>
|
10 | </a>
|
11 | <a href="https://npm-stat.com/charts.html?package=tabling">
|
12 | <img src="https://badgen.net/npm/dw/tabling?labelColor=black&color=black&cache=600" alt="downloads"/>
|
13 | </a>
|
14 | <a href="https://packagephobia.com/result?p=tabling">
|
15 | <img src="https://badgen.net/packagephobia/install/tabling?labelColor=black&color=black" alt="size"/>
|
16 | </a>
|
17 | <a href="https://bundlephobia.com/result?p=tabling">
|
18 | <img src="https://badgen.net/bundlephobia/minzip/tabling?labelColor=black&color=black" alt="size"/>
|
19 | </a>
|
20 | </span>
|
21 |
|
22 | <br />
|
23 | <br />
|
24 | </div>
|
25 |
|
26 | Commit a getter's result for one-time evaluation.
|
27 |
|
28 | ## ⚙️ Install
|
29 |
|
30 | ```sh
|
31 | npm add tabling
|
32 | ```
|
33 |
|
34 | ## 🚀 Usage
|
35 |
|
36 | ```ts
|
37 | import { tabling } from "tabling";
|
38 |
|
39 | const myObject = tabling({
|
40 | get answer() {
|
41 | return discover_the_meaning_of_life();
|
42 | },
|
43 | });
|
44 |
|
45 | myObject.answer; // 42
|
46 | ```
|
47 |
|
48 | Where ordinarily, that would look like `{ answer: discover_the_meaning_of_life() }` for a value
|
49 | somebody may never read.
|
50 |
|
51 | ## 🔎 API
|
52 |
|
53 | #### Module: [`tabling`](./src/index.js)
|
54 |
|
55 | The main and _default_ module and us `Proxy` based. Everything is lazy here, the object is built-up
|
56 | over which keys are consumed.
|
57 |
|
58 | > No upfront cost, and slightly slower read time.
|
59 |
|
60 | #### Module: [`tabling/warm`](./src/warm.js)
|
61 |
|
62 | A `object` based implementation, whereby the result is setup at evaluation time.
|
63 |
|
64 | > Upfront cost, but no read time.
|
65 |
|
66 | ### 🤔 But which one should I use?
|
67 |
|
68 | Naturally riddled with assumptions. But If you see the benchmarks below, generally the advice is.
|
69 |
|
70 | 1. if you've got a long-running process with many reads, the `/warm` sub-module is what youre after.
|
71 | - think like a web-server, where the object is module-scope.
|
72 | 2. browsers, you're probably after the `default` (proxy based) api. Very minimal reads, and want
|
73 | fast as possible startup time.
|
74 |
|
75 | So with that, and by no means bullet-proof answer;
|
76 |
|
77 | - server — `tabling/warm`
|
78 | - browser - `tabling`
|
79 |
|
80 | ## 💨 Benchmark
|
81 |
|
82 | > via the [`/bench`](/bench) directory with Node v17.2.0
|
83 |
|
84 | ```
|
85 | benchmark :: setup
|
86 | default x 2,442,456 ops/sec ±1.92% (89 runs sampled)
|
87 | warm x 503,581 ops/sec ±0.69% (93 runs sampled)
|
88 |
|
89 | benchmark :: jit
|
90 | default x 2,168,685 ops/sec ±1.25% (91 runs sampled)
|
91 | warm x 430,936 ops/sec ±1.49% (91 runs sampled)
|
92 |
|
93 | benchmark :: aot
|
94 | default x 27,579,584 ops/sec ±0.52% (89 runs sampled)
|
95 | warm x 133,821,620 ops/sec ±0.34% (93 runs sampled)
|
96 | ```
|
97 |
|
98 | > **setup** — the time to construct the object, _without_ reading from it.
|
99 | >
|
100 | > **jit** — the object is constructed on the hot path, and read from immediately. Think "request
|
101 | > bound" objects.
|
102 | >
|
103 | > **aot** — the object is constructed _ahead of time_, and read later on the hot path. Think "module
|
104 | > scope" objects.
|
105 |
|
106 | ## ❤️ Thanks
|
107 |
|
108 | Special thanks to [@wongmjane](http://twitter.com/wongmjane) for idea!
|
109 |
|
110 | ## License
|
111 |
|
112 | MIT © [Marais Rossouw](https://marais.io)
|