{"id":20767026,"url":"https://github.com/binded/persistent-memoize","last_synced_at":"2025-05-11T08:34:06.244Z","repository":{"id":50702361,"uuid":"59332964","full_name":"binded/persistent-memoize","owner":"binded","description":"Memoize across time \u0026 processes. Caches to your local file system, Amazon S3, Google Drive, Google Cloud, PostgreSQL or even BitTorrent :wink:","archived":true,"fork":false,"pushed_at":"2016-09-09T20:02:08.000Z","size":21,"stargazers_count":27,"open_issues_count":0,"forks_count":3,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-04-27T12:02:17.289Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/binded.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-05-21T00:00:18.000Z","updated_at":"2025-03-11T07:58:54.000Z","dependencies_parsed_at":"2022-09-24T14:00:43.496Z","dependency_job_id":null,"html_url":"https://github.com/binded/persistent-memoize","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/binded%2Fpersistent-memoize","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/binded%2Fpersistent-memoize/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/binded%2Fpersistent-memoize/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/binded%2Fpersistent-memoize/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/binded","download_url":"https://codeload.github.com/binded/persistent-memoize/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253540462,"owners_count":21924522,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-17T11:27:20.785Z","updated_at":"2025-05-11T08:34:05.944Z","avatar_url":"https://github.com/binded.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# persistent-memoize\n\n[![Build Status](https://travis-ci.org/blockai/persistent-memoize.svg?branch=master)](https://travis-ci.org/blockai/persistent-memoize)\n\n**DEPRECATION WARNING:** We've decided to deprecate this module in\nfavour of [blockai/cloud-cache](https://github.com/blockai/cloud-cache)\nwhich works mostly the same except it doesn't try to automatically guess\nkey names (those heuristics were a bit confusing) and clearly separates\nPromise vs Stream based APIs.\n\n[Memoize](https://en.wikipedia.org/wiki/Memoization) / cache arbitrary\nfunctions to the local file system, Amazon S3, Google Drive, Google\nCloud, PostgreSQL, Bittorrent, etc.\n\nDesigned to work across different processes or restarts. Functions must\nbe uniquely identified by the user through a `name` argument. Also uses\nsmart heuristics to further identify like using the `package.json`'s\n`name` and `version` properties.\n\nSupports optional cache expiry through a `maxAge` argument.\n\nSupports promise and stream returning functions.\n\nAny\n[abstract-blob-store](https://github.com/maxogden/abstract-blob-store)\ncompatible store is supported.\n\n[![blob-store-compatible](https://raw.githubusercontent.com/maxogden/abstract-blob-store/master/badge.png)](https://github.com/maxogden/abstract-blob-store)\n\n## Install\n\n```\nnpm install --save persistent-memoize\n```\n\n## Usage\n\n### initMemoize(blobStore [, opts])\n\nReturns a **memoize()** function.\n\n**blobStore** should be an [abstract-blob-store](https://github.com/maxogden/abstract-blob-store).\n\n**opts** (optional) configuration object\n\n**opts.name** (defaults to the `npm_package_name` environment variable\nwhich is automatically set when running script through npm)\n\nUsed when generating the key used by the blob store. See Key Generation.\n\n**opts.version** (defaults to the `npm_package_version` environment\nvariable which is automatically set when running script through npm)\n\nUsed when generating the key used by the blob store. We suggest\nsetting the version to `'latest'` or `null` if you chose to version\nfunctions individually. This prevents needlessly invalidating\nthe cache when the app version is bumped but the individual function\nversions haven't changed. See Key Generation.\n\n**opts.maxAge** (defaults to `Infinity`)\n\nSpecifies after how long (in milliseconds since it was last updated) a\ncached value is considered stale/expired. Can be overriden through\n`memoize()` options.\n\n### memoize(fn, name [, opts])\n\n**opts.disable** (defaults to `false`)\n\nCan be used to completely disable memoization. This can be useful for\ndebugging.\n\n**fn**\n\nThe function to memoize.\n\nIn order for memoization to work as expected, the return value of `fn`\nmust exclusively depend on its arguments and nothing else. It also must\nnot produce any visible side effects.\n\n[From Wikipedia](https://en.wikipedia.org/wiki/Memoization):\n\nA function can only be memoized if it is [referentially\ntransparent](https://en.wikipedia.org/wiki/Referential_transparency);\nthat is, only if calling the function has exactly the same effect as\nreplacing that function call with its return value.\n\nIn addition, all `fn` arguments and its return value must be compatible\nwith `JSON.stringify`.\n\n[json-stable-stringify](https://github.com/substack/json-stable-stringify)\nis used to deterministically generate a string from arguments which is\nthen hashed with sha1 to compute a unique key.\n\n**name**\n\nSince we want the memoization to work across different processes or\nrestarts, we must name the function so that it can uniquely be\nidentified. See Key Generation.\n\n**opts** optional configuration object\n\n**opts.version**\n\nA version can optionally be specified if you wish to version functions\nindividually instead of using a global version number. See Key\nGeneration.\n\n**opts.maxAge**\n\nOverrides the default `maxAge` value.\n\n### Key generation\n\n`persistent-memoize` is designed to memoize functions across processes\nand restarts. In order to do that reliably, functions must be named and\nversioned explicitly.\n\nThe algorithm to generate keys for specific function calls is as follows:\n\n```\nglobalName/globalVersion/name/version/argumentHash\n```\n\nWhere `globalName` and `globalVersion` are respectively the `opts.name`\nand `opts.version` values passed to `initMemoize(store, opts)`. `name` and\n`version` are respectively the `name` argument and `opts.version` value\npassed to `memoize(fn, name, opts)` .\n\n`argumentHash` is, in pseudo code:\n\n```javascript\nargumentHash = sha1(stringifyToJson(arguments))\n```\n\nWhere `arguments` is an array of arguments passed to the memoized\nfunction and `stringifyToJson` is a call to\n[json-stable-stringify](https://github.com/substack/json-stable-stringify)\nwhich is similar to `JSON.stringify` but more deterministic (e.g. order\nof object keys doesn't matter).\n\n## Examples\n\n```javascript\nimport initMemoize from 'persistent-memoize'\nimport initBlobStore from 'fs-blob-store'\n\nconst memoize = initMemoize(initBlobStore())\n\nconst someSlowFunction = (i) =\u003e Promise.resolve(`your number is ${i}`)\nconst getValue = memoize(someSlowFunction, 'someSlowFunction')\n\ngetValue(2)\n  // caches result in blob store and returns it\n  .then((str) =\u003e console.log(str))\n  // now that the result is cached, it will return it from cache\n  .then((str) =\u003e console.log(str))\n```\n\nBoilerplate:\n\n```javascript\nimport persistentMemoize from 'persistent-memoize'\nimport fetch from 'node-fetch'\nimport http from 'http'\nimport initBlobStore from 's3-blob-store'\nimport aws from 'aws-sdk'\n\nconst store = initBlobStore({\n  client: new aws.S3({\n    accessKeyId: process.env.S3_ACCESS_KEY,\n    secretAccessKey: process.env.S3_SECRET_KEY\n  }),\n  bucket: 'mybucket',\n})\n\nconst memoize = persistentMemoize(store)\n\n// Memoize fetch calls (fetch returns a promise)\n// Cache will be invalidated when version in `package.json`\n// is bumped OR when cache is expired (see maxAge option)\nconst memoizedFetch = memoize((...args) =\u003e (\n  fetch(...args)\n    .then((response) =\u003e {\n      // If an error is thrown, the funciton call won't be memoized\n      if (!response.ok) throw new Error('oops, problem with request')\n      return response.text()\n    })\n), 'memoizedFetch')\n\n// Functions can be versioned individually\nconst memoizeNoVersion = persistentMemoize(store, { version: null })\n\n// Sync function. Be careful when memoizing a sync function as it\n// doesn't create a drop in replacement because the memoized will\n// version be async and returns a promise.\nconst expensiveComputation = memoizeNoVersion((i) =\u003e {\n  // some expensive computation :)\n  return i + 1\n}, 'expensive-computation', { version: 'v1' })\n```\n\nSee [./test](./test) for more examples.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbinded%2Fpersistent-memoize","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbinded%2Fpersistent-memoize","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbinded%2Fpersistent-memoize/lists"}