Spaces:
Running
Running
| # reusify | |
| [![npm version][npm-badge]][npm-url] | |
| [![Build Status][travis-badge]][travis-url] | |
| [![Coverage Status][coveralls-badge]][coveralls-url] | |
| Reuse your objects and functions for maximum speed. This technique will | |
| make any function run ~10% faster. You call your functions a | |
| lot, and it adds up quickly in hot code paths. | |
| ``` | |
| $ node benchmarks/createNoCodeFunction.js | |
| Total time 53133 | |
| Total iterations 100000000 | |
| Iteration/s 1882069.5236482036 | |
| $ node benchmarks/reuseNoCodeFunction.js | |
| Total time 50617 | |
| Total iterations 100000000 | |
| Iteration/s 1975620.838848608 | |
| ``` | |
| The above benchmark uses fibonacci to simulate a real high-cpu load. | |
| The actual numbers might differ for your use case, but the difference | |
| should not. | |
| The benchmark was taken using Node v6.10.0. | |
| This library was extracted from | |
| [fastparallel](http://npm.im/fastparallel). | |
| ## Example | |
| ```js | |
| var reusify = require('reusify') | |
| var fib = require('reusify/benchmarks/fib') | |
| var instance = reusify(MyObject) | |
| // get an object from the cache, | |
| // or creates a new one when cache is empty | |
| var obj = instance.get() | |
| // set the state | |
| obj.num = 100 | |
| obj.func() | |
| // reset the state. | |
| // if the state contains any external object | |
| // do not use delete operator (it is slow) | |
| // prefer set them to null | |
| obj.num = 0 | |
| // store an object in the cache | |
| instance.release(obj) | |
| function MyObject () { | |
| // you need to define this property | |
| // so V8 can compile MyObject into an | |
| // hidden class | |
| this.next = null | |
| this.num = 0 | |
| var that = this | |
| // this function is never reallocated, | |
| // so it can be optimized by V8 | |
| this.func = function () { | |
| if (null) { | |
| // do nothing | |
| } else { | |
| // calculates fibonacci | |
| fib(that.num) | |
| } | |
| } | |
| } | |
| ``` | |
| The above example was intended for synchronous code, let's see async: | |
| ```js | |
| var reusify = require('reusify') | |
| var instance = reusify(MyObject) | |
| for (var i = 0; i < 100; i++) { | |
| getData(i, console.log) | |
| } | |
| function getData (value, cb) { | |
| var obj = instance.get() | |
| obj.value = value | |
| obj.cb = cb | |
| obj.run() | |
| } | |
| function MyObject () { | |
| this.next = null | |
| this.value = null | |
| var that = this | |
| this.run = function () { | |
| asyncOperation(that.value, that.handle) | |
| } | |
| this.handle = function (err, result) { | |
| that.cb(err, result) | |
| that.value = null | |
| that.cb = null | |
| instance.release(that) | |
| } | |
| } | |
| ``` | |
| Also note how in the above examples, the code, that consumes an istance of `MyObject`, | |
| reset the state to initial condition, just before storing it in the cache. | |
| That's needed so that every subsequent request for an instance from the cache, | |
| could get a clean instance. | |
| ## Why | |
| It is faster because V8 doesn't have to collect all the functions you | |
| create. On a short-lived benchmark, it is as fast as creating the | |
| nested function, but on a longer time frame it creates less | |
| pressure on the garbage collector. | |
| ## Other examples | |
| If you want to see some complex example, checkout [middie](https://github.com/fastify/middie) and [steed](https://github.com/mcollina/steed). | |
| ## Acknowledgements | |
| Thanks to [Trevor Norris](https://github.com/trevnorris) for | |
| getting me down the rabbit hole of performance, and thanks to [Mathias | |
| Buss](http://github.com/mafintosh) for suggesting me to share this | |
| trick. | |
| ## License | |
| MIT | |
| [npm-badge]: https://badge.fury.io/js/reusify.svg | |
| [npm-url]: https://badge.fury.io/js/reusify | |
| [travis-badge]: https://api.travis-ci.org/mcollina/reusify.svg | |
| [travis-url]: https://travis-ci.org/mcollina/reusify | |
| [coveralls-badge]: https://coveralls.io/repos/mcollina/reusify/badge.svg?branch=master&service=github | |
| [coveralls-url]: https://coveralls.io/github/mcollina/reusify?branch=master | |