You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							304 lines
						
					
					
						
							6.2 KiB
						
					
					
				
			
		
		
	
	
							304 lines
						
					
					
						
							6.2 KiB
						
					
					
				| # 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
 | |
| 
 |