chushihua
This commit is contained in:
+303
@@ -0,0 +1,303 @@
|
||||
# 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
|
||||
|
||||
Reference in New Issue
Block a user