25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.

3 yıl önce
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. # memoize-one
  2. A memoization library that only caches the result of the most recent arguments.
  3. [![Build Status](https://travis-ci.org/alexreardon/memoize-one.svg?branch=master)](https://travis-ci.org/alexreardon/memoize-one)
  4. [![npm](https://img.shields.io/npm/v/memoize-one.svg)](https://www.npmjs.com/package/memoize-one)
  5. [![dependencies](https://david-dm.org/alexreardon/memoize-one.svg)](https://david-dm.org/alexreardon/memoize-one)
  6. [![Downloads per month](https://img.shields.io/npm/dm/memoize-one.svg)](https://www.npmjs.com/package/memoize-one)
  7. [![min](https://img.shields.io/bundlephobia/min/memoize-one.svg)](https://www.npmjs.com/package/memoize-one)
  8. [![minzip](https://img.shields.io/bundlephobia/minzip/memoize-one.svg)](https://www.npmjs.com/package/memoize-one)
  9. ## Rationale
  10. Cache invalidation is hard:
  11. > There are only two hard things in Computer Science: cache invalidation and naming things.
  12. >
  13. > *Phil Karlton*
  14. So keep things simple and just use a cache size of one!
  15. Unlike other memoization libraries, `memoize-one` only remembers the latest arguments and result. No need to worry about cache busting mechanisms such as `maxAge`, `maxSize`, `exclusions` and so on which can be prone to memory leaks. `memoize-one` simply remembers the last arguments, and if the function is next called with the same arguments then it returns the previous result.
  16. ## Usage
  17. ### Standard usage
  18. ```js
  19. import memoizeOne from 'memoize-one';
  20. const add = (a, b) => a + b;
  21. const memoizedAdd = memoizeOne(add);
  22. memoizedAdd(1, 2); // 3
  23. memoizedAdd(1, 2); // 3
  24. // Add function is not executed: previous result is returned
  25. memoizedAdd(2, 3); // 5
  26. // Add function is called to get new value
  27. memoizedAdd(2, 3); // 5
  28. // Add function is not executed: previous result is returned
  29. memoizedAdd(1, 2); // 3
  30. // Add function is called to get new value.
  31. // While this was previously cached,
  32. // it is not the latest so the cached result is lost
  33. ```
  34. ### Custom equality function
  35. You can also pass in a custom function for checking the equality of two items.
  36. ```js
  37. import memoizeOne from 'memoize-one';
  38. import deepEqual from 'lodash.isEqual';
  39. const identity = x => x;
  40. const defaultMemoization = memoizeOne(identity);
  41. const customMemoization = memoizeOne(identity, deepEqual);
  42. const result1 = defaultMemoization({foo: 'bar'});
  43. const result2 = defaultMemoization({foo: 'bar'});
  44. result1 === result2 // false - difference reference
  45. const result3 = customMemoization({foo: 'bar'});
  46. const result4 = customMemoization({foo: 'bar'});
  47. result3 === result4 // true - arguments are deep equal
  48. ```
  49. #### Equality function type signature
  50. Here is the expected [flow](http://flowtype.org) type signature for a custom equality function:
  51. ```js
  52. type EqualityFn = (a: mixed, b: mixed) => boolean;
  53. ```
  54. #### Custom equality function with multiple arguments
  55. If the function you want to memoize takes multiple arguments, your custom equality function will be called once for each argument and will be passed each argument's new value and last value.
  56. ```js
  57. import memoizeOne from 'memoize-one';
  58. const makeCountObj = (first, second, third) => ({
  59. first: first.count,
  60. second: second.count,
  61. third: third.count,
  62. });
  63. const areCountPropertiesEqual = (newArg, lastArg) => newArg.count === lastArg.count;
  64. // runs once for first's new and last values, once for second's, etc.
  65. const memoizedMakeCountObj = memoizeOne(makeCountObj, areCountPropertiesEqual);
  66. const result1 = memoizedMakeCountObj(
  67. {a: '?', count: 1},
  68. {a: '$', count: 2},
  69. {a: '#', count: 3}
  70. );
  71. const result2 = memoizedMakeCountObj(
  72. {b: null, count: 1},
  73. {b: null, count: 2},
  74. {b: null, count: 3}
  75. );
  76. result1 === result2; // true - same reference
  77. ```
  78. ## Installation
  79. ```bash
  80. # yarn
  81. yarn add memoize-one
  82. # npm
  83. npm install memoize-one --save
  84. ```
  85. ## Module usage
  86. ### ES6 module
  87. ```js
  88. import memoizeOne from 'memoize-one';
  89. ```
  90. ### CommonJS
  91. If you are in a CommonJS environment (eg [Node](https://nodejs.org)), then **you will need to add `.default` to your import**:
  92. ```js
  93. const memoizeOne = require('memoize-one').default;
  94. ```
  95. ## `this`
  96. ### `memoize-one` correctly respects `this` control
  97. This library takes special care to maintain, and allow control over the the `this` context for **both** the original function being memoized as well as the returned memoized function. Both the original function and the memoized function's `this` context respect [all the `this` controlling techniques](https://github.com/getify/You-Dont-Know-JS/blob/master/this%20%26%20object%20prototypes/ch2.md):
  98. - new bindings (`new`)
  99. - explicit binding (`call`, `apply`, `bind`);
  100. - implicit binding (call site: `obj.foo()`);
  101. - default binding (`window` or `undefined` in `strict mode`);
  102. - fat arrow binding (binding to lexical `this`)
  103. - ignored this (pass `null` as `this` to explicit binding)
  104. ### Changes to `this` is considered an argument change
  105. Changes to the running context (`this`) of a function can result in the function returning a different value even though its arguments have stayed the same:
  106. ```js
  107. function getA() {
  108. return this.a;
  109. }
  110. const temp1 = {
  111. a: 20,
  112. };
  113. const temp2 = {
  114. a: 30,
  115. }
  116. getA.call(temp1); // 20
  117. getA.call(temp2); // 30
  118. ```
  119. Therefore, in order to prevent against unexpected results, `memoize-one` takes into account the current execution context (`this`) of the memoized function. If `this` is different to the previous invocation then it is considered a change in argument. [further discussion](https://github.com/alexreardon/memoize-one/issues/3).
  120. Generally this will be of no impact if you are not explicity controlling the `this` context of functions you want to memoize with [explicit binding](https://github.com/getify/You-Dont-Know-JS/blob/master/this%20%26%20object%20prototypes/ch2.md#explicit-binding) or [implicit binding](https://github.com/getify/You-Dont-Know-JS/blob/master/this%20%26%20object%20prototypes/ch2.md#implicit-binding). `memoize-One` will detect when you are manipulating `this` and will then consider the `this` context as an argument. If `this` changes, it will re-execute the original function even if the arguments have not changed.
  121. ## When your result function `throw`s
  122. > There is no caching when your result function throws
  123. If your result function `throw`s then the memoized function will also throw. The throw will not break the memoized functions existing argument cache. It means the memoized function will pretend like it was never called with arguments that made it `throw`.
  124. ```js
  125. const canThrow = (name: string) => {
  126. console.log('called');
  127. if(name === 'throw') {
  128. throw new Error(name);
  129. }
  130. return { name };
  131. }
  132. const memoized = memoizeOne(canThrow);
  133. const value1 = memoized('Alex');
  134. // console.log => 'called'
  135. const value2 = memoized('Alex');
  136. // result function not called
  137. console.log(value1 === value2);
  138. // console.log => true
  139. try {
  140. memoized('throw');
  141. // console.log => 'called'
  142. } catch(e) {
  143. firstError = e;
  144. }
  145. try {
  146. memoized('throw');
  147. // console.log => 'called'
  148. // the result function was called again even though it was called twice
  149. // with the 'throw' string
  150. } catch(e) {
  151. secondError = e;
  152. }
  153. console.log(firstError !== secondError);
  154. const value3 = memoized('Alex');
  155. // result function not called as the original memoization cache has not been busted
  156. console.log(value1 === value3);
  157. // console.log => true
  158. ```
  159. ## Performance :rocket:
  160. ### Tiny
  161. `memoize-one` is super lightweight at [![min](https://img.shields.io/bundlephobia/min/memoize-one.svg?label=)](https://www.npmjs.com/package/memoize-one) minified and [![minzip](https://img.shields.io/bundlephobia/minzip/memoize-one.svg?label=)](https://www.npmjs.com/package/memoize-one) gzipped. (`1KB` = `1,024 Bytes`)
  162. ### Extremely fast
  163. `memoize-one` performs better or on par with than other popular memoization libraries for the purpose of remembering the latest invocation.
  164. **Results**
  165. - [simple arguments](https://www.measurethat.net/Benchmarks/ShowResult/4452)
  166. - [complex arguments](https://www.measurethat.net/Benchmarks/ShowResult/4488)
  167. The comparisions are not exhaustive and are primiarly to show that `memoize-one` accomplishes remembering the latest invocation really fast. The benchmarks do not take into account the differences in feature sets, library sizes, parse time, and so on.
  168. ## Code health :thumbsup:
  169. - Tested with all built in [JavaScript types](https://github.com/getify/You-Dont-Know-JS/blob/master/types%20%26%20grammar/ch1.md).
  170. - 100% code coverage
  171. - [Continuous integration](https://travis-ci.org/alexreardon/memoize-one) to run tests and type checks.
  172. - [`Flow` types](http://flowtype.org) for safer internal execution and external consumption. Also allows for editor autocompletion.
  173. - Follows [Semantic versioning (2.0)](http://semver.org/) for safer consumption.
  174. - No dependencies