Skip to content

Commit

Permalink
feat: add .noWrapError() switch
Browse files Browse the repository at this point in the history
  • Loading branch information
jedwards1211 committed Aug 14, 2020
1 parent 247701f commit c6febe0
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 5 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ poll(() => superagent.get('http://google.com'), 1000)
.then(() => console.log("You're connected to the internet!"))
```

## `poll(fn, interval)`
## `poll(fn, interval, [options])`

Begins calling `fn` every `interval` milliseconds until the condition passes
(which defaults to `fn` didn't throw an `Error` or return a rejected `Promise`).
Expand Down Expand Up @@ -56,3 +56,5 @@ You can specify a timeout (in milliseconds) by calling `.timeout` on the returne
```js
poll(...).timeout(30000) // time out after 30 seconds
```

If you call `.noWrapError()` on the returned `Promise`, it won't wrap rejection errors.
17 changes: 13 additions & 4 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export type Poller<T> = Promise<T> & {
cancel(): void;
until(condition: UntilCondition<T>): Poller<T>;
timeout(ms: number): Poller<T>;
noWrapError(): Poller<T>;
}

export type CallContext<T> = {
Expand All @@ -14,17 +15,17 @@ export type CallContext<T> = {
fail(error: Error): void;
pass(value: T): void;
}

function poll<T>(
fn: (info: CallContext<T>) => T | Promise<T>,
interval: number
interval: number,
): Poller<T> {
let fail, pass
let attemptNumber = 0
let until = (error: ?Error, result?: T) => !error
let timeout: ?number
let timeoutId: ?any
let lastError: ?Error
let wrapError: boolean = true

if (!Number.isFinite(interval) || interval < 0) {
throw new Error(`invalid interval: ${interval}`)
Expand Down Expand Up @@ -65,8 +66,12 @@ function poll<T>(
const nextTime = now + interval
if (timeout != null && nextTime - startTime > timeout) {
let message = "timed out waiting for polling to succeed"
if (lastError) message += `; last error: ${lastError.stack}`
reject(new Error(message))
if (wrapError) {
if (lastError) message += `; last error: ${lastError.stack}`
reject(new Error(message))
} else {
reject(lastError || new Error(message))
}
} else {
const delay = Math.max(0, nextTime - Date.now())
timeoutId = setTimeout(attempt, delay)
Expand All @@ -86,6 +91,10 @@ function poll<T>(
timeout = ms
return promise
}
;(promise: any).noWrapError = () => {
wrapError = false
return promise
}

return (promise: any)
}
Expand Down
11 changes: 11 additions & 0 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,17 @@ describe('poll', function () {
expect(error.message).to.match(/timed out/i)
expect(error.message).to.match(/last error: Error: test!/i)
})
it(`doesn't wrap error if wrapError: false`, async () => {
let numAttempts
let error
await poll(({attemptNumber, elapsedTime}: CallContext<void>) => {
numAttempts = attemptNumber + 1
if (elapsedTime < 500) throw new Error('test!')
}, 100).timeout(250).noWrapError().catch(err => error = err)
expect(numAttempts).to.equal(3)
if (!error) throw new Error('expected error to be thrown')
expect(error.message).to.equal('test!')
})
it('allows fn to manually pass', async () => {
const result = await poll(({attemptNumber, pass}: CallContext<number>): any => {
if (attemptNumber === 3) pass(attemptNumber)
Expand Down

0 comments on commit c6febe0

Please sign in to comment.