| # tryer |
| |
| [](https://gitlab.com/philbooth/tryer/pipelines) |
| [](https://www.npmjs.com/package/tryer) |
| [](https://www.npmjs.com/package/tryer) |
| [](https://opensource.org/licenses/MIT) |
| |
| |
| Because everyone loves a tryer! |
| Conditional |
| and repeated |
| function invocation |
| for node |
| and browser. |
| |
| * [Say what?](#say-what) |
| * [What size is it?](#what-size-is-it) |
| * [How do I install it?](#how-do-i-install-it) |
| * [How do I use it?](#how-do-i-use-it) |
| * [Loading the library](#loading-the-library) |
| * [Calling the exported function](#calling-the-exported-function) |
| * [Examples](#examples) |
| * [How do I set up the dev environment?](#how-do-i-set-up-the-dev-environment) |
| * [What license is it released under?](#what-license-is-it-released-under) |
| |
| ## Say what? |
| |
| Sometimes, |
| you want to defer |
| calling a function |
| until a certain |
| pre-requisite condition is met. |
| Other times, |
| you want to |
| call a function |
| repeatedly |
| until some post-requisite condition |
| is satisfied. |
| Occasionally, |
| you might even want |
| to do both |
| for the same function. |
| |
| To save you writing |
| explicit conditions |
| and loops |
| on each of those occasions, |
| `tryer` implements |
| a predicate-based approach |
| that hides the cruft |
| behind a simple, |
| functional interface. |
| |
| Additionally, |
| it allows you to easily specify |
| retry intervals |
| and limits, |
| so that your code |
| doesn't hog the CPU. |
| It also supports |
| exponential backoff |
| of retry intervals, |
| which can be useful |
| when handling |
| indefinite error states |
| such as network failure. |
| |
| ## What size is it? |
| |
| 5.6 kb unminified with comments, 1.1 kb minified, 0.5 kb minified + gzipped. |
| |
| ## How do I install it? |
| |
| Via npm: |
| |
| ``` |
| npm i tryer --save |
| ``` |
| |
| Or if you just want the git repo: |
| |
| ``` |
| git clone git@gitlab.com:philbooth/tryer.git |
| ``` |
| |
| ## How do I use it? |
| |
| ### Loading the library |
| |
| If you are running in |
| Node.js |
| or another CommonJS-style |
| environment, |
| you can `require` |
| tryer like so: |
| |
| ```javascript |
| const tryer = require('tryer'); |
| ``` |
| |
| It also the supports |
| the AMD-style format |
| preferred by Require.js. |
| |
| If you are |
| including `tryer` |
| with an HTML `<script>` tag, |
| or neither of the above environments |
| are detected, |
| it will be exported globally as `tryer`. |
| |
| ### Calling the exported function |
| |
| `tryer` is a function |
| that can be invoked to |
| call other functions |
| conditionally and repeatedly, |
| without the need for |
| explicit `if` statements |
| or loops in your own code. |
| |
| `tryer` takes one argument, |
| an options object |
| that supports |
| the following properties: |
| |
| * `action`: |
| The function that you want to invoke. |
| If `action` returns a promise, |
| iterations will not end |
| until the promise is resolved or rejected. |
| Alternatively, |
| `action` may take a callback argument, `done`, |
| to signal that it is asynchronous. |
| In that case, |
| you are responsible |
| for calling `done` |
| when the action is finished. |
| If `action` is not set, |
| it defaults to an empty function. |
| |
| * `when`: |
| A predicate |
| that tests the pre-condition |
| for invoking `action`. |
| Until `when` returns true |
| (or a truthy value), |
| `action` will not be called. |
| Defaults to |
| a function that immediately returns `true`. |
| |
| * `until`: |
| A predicate |
| that tests the post-condition |
| for invoking `action`. |
| After `until` returns true |
| (or a truthy value), |
| `action` will no longer be called. |
| Defaults to |
| a function that immediately returns `true`. |
| |
| * `fail`: |
| The error handler. |
| A function |
| that will be called |
| if `limit` falsey values |
| are returned by `when` or `until`. |
| Defaults to an empty function. |
| |
| * `pass`: |
| Success handler. |
| A function |
| that will be called |
| after `until` has returned truthily. |
| Defaults to an empty function. |
| |
| * `limit`: |
| Failure limit, |
| representing the maximum number |
| of falsey returns from `when` or `until` |
| that will be permitted |
| before invocation is deemed to have failed. |
| A negative number |
| indicates that the attempt |
| should never fail, |
| instead continuing |
| for as long as `when` and `until` |
| have returned truthy values. |
| Defaults to `-1`. |
| |
| * `interval`: |
| The retry interval, |
| in milliseconds. |
| A negative number indicates |
| that each subsequent retry |
| should wait for twice the interval |
| from the preceding iteration |
| (i.e. exponential backoff). |
| The default value is `-1000`, |
| signifying that |
| the initial retry interval |
| should be one second |
| and that each subsequent attempt |
| should wait for double the length |
| of the previous interval. |
| |
| ### Examples |
| |
| ```javascript |
| // Attempt to insert a database record, waiting until `db.isConnected` |
| // before doing so. The retry interval is 1 second on each iteration |
| // and the call will fail after 10 attempts. |
| tryer({ |
| action: () => db.insert(record), |
| when: () => db.isConnected, |
| interval: 1000, |
| limit: 10, |
| fail () { |
| log.error('No database connection, terminating.'); |
| process.exit(1); |
| } |
| }); |
| ``` |
| |
| ```javascript |
| // Attempt to send an email message, optionally retrying with |
| // exponential backoff starting at 1 second. Continue to make |
| // attempts indefinitely until the call succeeds. |
| let sent = false; |
| tryer({ |
| action (done) { |
| smtp.send(email, error => { |
| if (! error) { |
| sent = true; |
| } |
| done(); |
| }); |
| }, |
| until: () => sent, |
| interval: -1000, |
| limit: -1 |
| }); |
| ``` |
| |
| ```javascript |
| // Poll a device at 30-second intervals, continuing indefinitely. |
| tryer({ |
| action: () => device.poll().then(response => handle(response)), |
| interval: 30000, |
| limit: -1 |
| }); |
| ``` |
| |
| ## How do I set up the dev environment? |
| |
| The dev environment relies on |
| [Chai], |
| [JSHint], |
| [Mocha], |
| [please-release-me], |
| [spooks.js] and |
| [UglifyJS]. |
| The source code is in |
| `src/tryer.js` |
| and the unit tests are in |
| `test/unit.js`. |
| |
| To install the dependencies: |
| |
| ``` |
| npm i |
| ``` |
| |
| To run the tests: |
| |
| ``` |
| npm t |
| ``` |
| |
| To lint the code: |
| |
| ``` |
| npm run lint |
| ``` |
| |
| To regenerate the minified lib: |
| |
| ``` |
| npm run minify |
| ``` |
| |
| ## What license is it released under? |
| |
| [MIT](COPYING) |
| |
| [chai]: http://chaijs.com/ |
| [jshint]: http://jshint.com/ |
| [mocha]: http://mochajs.org/ |
| [please-release-me]: https://gitlab.com/philbooth/please-release-me |
| [spooks.js]: https://gitlab.com/philbooth/spooks.js |
| [uglifyjs]: http://lisperator.net/uglifyjs/ |
| [license]: COPYING |
| |