A wrapper around Map that uses structural equality for key matching instead of the SameValueZero algorithm. This means that (for example) objects of equal but not referential value will point to the same DopeMap
entry. This can come with a slight performance tradeoff (see Benchmarks), so if your dataset is very large take that into consideration.
Ships with a hardcoded (dep-free) implementation of fast-json-stable-stringify and xxhashjs as its hashing function. You can supply a different hashing function in DopeMap's config (as long as it returns a string
or number
).
fafo here
yarn add @johnhaup/dope-map
In addition to standard Map methods
DopeMaps constructor accepts a second config
argument.
import { DopeMap } from "@johnhaup/dope-map";
import hashIt from "hash-it";
const dopeMap = new DopeMap(null, { hashFunction: hashIt });
Property | Type | Description |
---|---|---|
hashFunction |
(key: unknown) => string | number |
Custom hashing function for non-primitive keys. |
Method | Return Value |
---|---|
getEntries |
Array of [key, value] tuples in order of entry |
getKeys |
Array of keys in order of entry |
getValues |
Array of values in order of entry |
DopeMap's
generics are flipped from traditional Map
:
DopeMap<Value, Key = unknown> // Map<Key = any, Value = any>
Key is optional so you can just type the value and go crazy with the keys you pass.
import { DopeMap } from "@johnhaup/dope-map";
const apiCache = new DopeMap();
const filters = {
category: "electronics",
priceRange: [100, 500],
tags: ["sale"],
};
async function fetchProducts(query) {
if (apiCache.has(query)) {
console.log("Cache hit");
return apiCache.get(query);
}
console.log("Cache miss");
const response = await fetch(`/api/products?${new URLSearchParams(query)}`);
const data = await response.json();
apiCache.set(query, data);
return data;
}
await fetchProducts(filters);
await fetchProducts({
priceRange: [100, 500],
category: "electronics",
tags: ["sale"],
}); // <- Cache hit
import { DopeMap } from "@johnhaup/dope-map";
type ProductAttributes = {
color: string;
size: string;
material: string;
};
type Product = {
id: string;
price: number;
promoPrice: number | null;
title: string;
};
const initialEntries: [ProductAttributes, Product][] = [
[
{ color: "blue", size: "sm", material: "cotton" },
{ id: "13nl54l", title: "Cool Blue", price: 24.99, promoPrice: null },
],
[
{ color: "blue", size: "xs", material: "cotton" },
{ id: "909sadfj", title: "Cool Blue", price: 19.99, promoPrice: 9.99 },
],
];
const productMap = new DopeMap<Product>(initialEntries);
interface Props {
filters: Partial<ProductAttributes>;
}
function SelectedProduct({ filters }: Props) {
const product = useMemo(() => {
return productMap.get(filters);
}, [filters]);
if (!product) {
return null;
}
return (
<div>
<p>{product.title}</p>
<p>{product.price}</p>
<p>{product.promoPrice}</p>
</div>
);
}
Each Dope/Map grows to the iteration size. Averages of method time are below. All times are in milliseconds.
Map | Set | Get | Has | Delete |
---|---|---|---|---|
Map | 0.001 | 0.0 | 0.0 | 0.0 |
DopeMap | 0.004 (+0.003) | 0.002 (+0.002) | 0.001 (+0.001) | 0.002 (+0.001) |
DopeMap w/hash-it | 0.004 (+0.004) | 0.002 (+0.002) | 0.001 (+0.001) | 0.002 (+0.002) |
DopeMap V1 | 0.070 (+0.069) | 0.069 (+0.069) | 0.069 (+0.069) | 0.069 (+0.069) |
Map | Set | Get | Has | Delete |
---|---|---|---|---|
Map | 0.012 | 0.0 | 0.0 | 0.005 |
DopeMap | 0.047 (+0.036) | 0.028 (+0.027) | 0.016 (+0.016) | 0.024 (+0.019) |
DopeMap w/hash-it | 0.055 (+0.043) | 0.033 (+0.033) | 0.017 (+0.016) | 0.024 (+0.019) |
DopeMap V1 | 0.719 (+0.707) | 0.709 (+0.709) | 0.675 (+0.675) | 0.684 (+0.679) |
Map | Set | Get | Has | Delete |
---|---|---|---|---|
Map | 0.170 | 0.022 | 0.031 | 0.052 |
DopeMap | 0.681 (+0.511) | 0.523 (+0.501) | 0.188 (+0.157) | 0.310 (+0.258) |
DopeMap w/hash-it | 0.653 (+0.484) | 0.488 (+0.466) | 0.191 (+0.159) | 0.282 (+0.230) |
DopeMap V1 | 7.6 (+7.4) | 7.3 (+7.3) | 6.9 (+6.9) | 6.9 (+6.9) |
Map | Set | Get | Has | Delete |
---|---|---|---|---|
Map | 1.7 | 1.5 | 1.5 | 0.584 |
DopeMap | 7.3 (+5.7) | 5.9 (+4.4) | 5.5 (+4.0) | 3.1 (+2.5) |
DopeMap w/hash-it | 7.9 (+6.3) | 6.2 (+4.7) | 5.6 (+4.1) | 2.8 (+2.2) |
DopeMap V1 | 88.0 (+86.3) | 83.1 (+81.6) | 82.9 (+81.5) | 75.5 (+74.9) |
Map | Set | Get | Has | Delete |
---|---|---|---|---|
Map | 0.001 | 0.0 | 0.0 | 0.0 |
DopeMap | 0.002 (+0.001) | 0.001 (+0.001) | 0.0 | 0.001 |
DopeMap w/hash-it | 0.002 (+0.001) | 0.001 (+0.001) | 0.0 | 0.001 |
DopeMap V1 | 0.002 (+0.001) | 0.001 (+0.001) | 0.0 | 0.001 |
Map | Set | Get | Has | Delete |
---|---|---|---|---|
Map | 0.012 | 0.001 | 0.001 | 0.005 |
DopeMap | 0.033 (+0.021) | 0.013 (+0.012) | 0.003 (+0.003) | 0.006 (+0.001) |
DopeMap w/hash-it | 0.034 (+0.022) | 0.013 (+0.012) | 0.003 (+0.003) | 0.006 (+0.001) |
DopeMap V1 | 0.027 (+0.015) | 0.017 (+0.017) | 0.007 (+0.007) | 0.009 (+0.004) |
Map | Set | Get | Has | Delete |
---|---|---|---|---|
Map | 0.203 | 0.036 | 0.036 | 0.050 |
DopeMap | 0.377 (+0.174) | 0.195 (+0.159) | 0.031 (-0.006) | 0.060 (+0.010) |
DopeMap w/hash-it | 0.375 (+0.172) | 0.192 (+0.156) | 0.030 (-0.006) | 0.061 (+0.011) |
DopeMap V1 | 0.320 (+0.117) | 0.239 (+0.204) | 0.059 (+0.022) | 0.091 (+0.041) |
Map | Set | Get | Has | Delete |
---|---|---|---|---|
Map | 2.9 | 2.1 | 2.1 | 0.562 |
DopeMap | 5.4 (+2.5) | 3.0 (+0.879) | 2.9 (+0.771) | 0.596 (+0.034) |
DopeMap w/hash-it | 5.4 (+2.5) | 3.0 (+0.890) | 2.7 (+0.588) | 0.598 (+0.037) |
DopeMap V1 | 4.4 (+1.5) | 3.1 (+0.947) | 0.575 (-1.5) | 0.920 (+0.358) |