Skip to content

Commit

Permalink
Improve the docs and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
sindresorhus committed Sep 3, 2018
1 parent 594c42f commit f21bfc8
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 114 deletions.
1 change: 1 addition & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const createDelay = willResolve => (ms, {value, signal} = {}) => {
clearTimeout(timeoutId);
rejectFn(createAbortError());
};

const cleanup = () => {
if (signal) {
signal.removeEventListener('abort', signalListener);
Expand Down
8 changes: 4 additions & 4 deletions index.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import delay from '.';
(async () => {
expectType<void>(await delay(200));

expectType<string>(await delay(200, '🦄'));
expectType<number>(await delay(200, 0));
expectType<string>(await delay(200, {value: '🦄'}));
expectType<number>(await delay(200, {value: 0}));

expectType<never>(await delay.reject(200, '🦄'));
expectType<never>(await delay.reject(200, 0));
expectType<never>(await delay.reject(200, {value: '🦄'}));
expectType<never>(await delay.reject(200, {value: 0}));
})();
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
],
"devDependencies": {
"abort-controller": "^1.0.2",
"ava": "*",
"ava": "1.0.0-beta.8",
"currently-unhandled": "^0.4.1",
"in-range": "^1.0.0",
"time-span": "^2.0.0",
Expand Down
146 changes: 86 additions & 60 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,90 +26,116 @@ const delay = require('delay');
```


## Advanced usage
## API

```js
const delay = require('delay');
### delay(milliseconds, [options])

delay(100, { value: 'a result' })
.then(result => {
// Executed after 100 milliseconds
// result === 'a result';
});

// There's also `delay.reject()` which optionally accepts a value and rejects it `ms` later
delay.reject(100, { value: 'foo' }))
.then(x => blah()) // Never executed
.catch(err => {
// Executed 100 milliseconds later
// err === 'foo'
});

// You can settle the delay by calling `.clear()`
(async () => {
const delayedPromise = delay(1000, { value: 'done!' });
Create a promise which resolves after the specified `milliseconds`.

setTimeout(() => {
delayedPromise.clear();
}, 500);
### delay.reject(milliseconds, [options])

const result = await delayedPromise;
// 500 milliseconds later
// result === 'done!'
})();
Create a promise which rejects after the specified `milliseconds`.

// In the browser, you can abort the delay with an AbortSignal as the last parameter
// There is a ponyfill for NodeJS: https://www.npmjs.com/package/abort-controller
(async () => {
const abortController = new AbortController();
#### milliseconds

setTimeout(() => {
abortController.abort()
}, 500);
Type: `number`

try {
await delay(1000, { signal: abortController.signal });
} catch (err) {
// 500ms later:
// err.name === 'AbortError'
}
})();
```
Milliseconds to delay the promise.

#### options

## API
Type: `Object`

### delay(ms, [options])
##### value

Create a promise which resolves after the specified `ms`.
Type: `any`

### delay.reject(ms, [options])
Optional value to resolve or reject in the returned promise.

Create a promise which rejects after the specified `ms`.
##### signal

#### ms
Type: [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal)

Type: `number`
The returned promise will be rejected with an AbortError if the signal is aborted. AbortSignal is available in all modern browsers and there is a [ponyfill for Node.js](https://github.com/mysticatea/abort-controller).

Milliseconds to delay the promise.
### delayPromise.clear()

#### options.value
Clears the delay and settles the promise.

Type: `any`

Optional value to resolve or reject in the returned promise.
## Advanced usage

#### options.signal
Passing a value:

Type: [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal)
```js
const delay = require('delay');

Optional AbortSignal to abort the delay.
The returned Promise will be rejected with an AbortError when the signal is aborted.
AbortSignal is available in all modern browsers and there is a [ponyfill for NodeJS](https://www.npmjs.com/package/abort-controller).
(async() => {
const result = await delay(100, {value: '🦄'});

### delayPromise.clear()
// Executed after 100 milliseconds
console.log(result);
//=> '🦄'
})();
```

Clears the delay and settles the promise.
Using `delay.reject()`, which optionally accepts a value and rejects it `ms` later:

```js
const delay = require('delay');

(async () => {
try {
await delay.reject(100, {value: new Error('🦄')});

console.log('This is never executed');
} catch (error) {
// 100 milliseconds later
console.log(error);
//=> [Error: 🦄]
}
})();
```

You can settle the delay early by calling `.clear()`:

```js
const delay = require('delay');

(async () => {
const delayedPromise = delay(1000, {value: 'Done'});

setTimeout(() => {
delayedPromise.clear();
}, 500);

// 500 milliseconds later
console.log(await delayedPromise);
//=> 'Done'
})();
```

You can abort the delay with an AbortSignal:

```js
const delay = require('delay');

(async () => {
const abortController = new AbortController();

setTimeout(() => {
abortController.abort();
}, 500);

try {
await delay(1000, {signal: abortController.signal});
} catch (error) {
// 500 milliseconds later
console.log(error.name)
//=> 'AbortError'
}
})();
```


## Related
Expand Down
88 changes: 39 additions & 49 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,28 +15,26 @@ test('returns a resolved promise', async t => {

test('returns a rejected promise', async t => {
const end = timeSpan();
try {
await m.reject(50, {value: new Error('foo')});
t.fail();
} catch (err) {
t.is(err.message, 'foo', 'promise is rejected with the second argument');
t.true(inRange(end(), 30, 70), 'is delayed');
}
await t.throwsAsync(
m.reject(50, {value: new Error('foo')}),
'foo'
);
t.true(inRange(end(), 30, 70), 'is delayed');
});

test('able to resolve a falsie value', async t => {
test('able to resolve a falsy value', async t => {
t.is(
await m(50, {value: 0}),
0
);
});

test('able to reject a falsie value', async t => {
test('able to reject a falsy value', async t => {
t.plan(1);
try {
await m.reject(50, {value: false});
} catch (err) {
t.is(err, false);
} catch (error) {
t.is(error, false);
}
});

Expand Down Expand Up @@ -76,61 +74,53 @@ test('can clear a delayed resolution', async t => {

test('can clear a delayed rejection', async t => {
const end = timeSpan();
const delayPromise = m.reject(1000, {value: 'error!'});
const delayPromise = m.reject(1000, {value: new Error('error!')});
delayPromise.clear();

await t.throws(delayPromise, /error!/);
await t.throwsAsync(delayPromise, /error!/);
t.true(end() < 30);
});

test('resolution can be aborted with an AbortSignal', async t => {
const end = timeSpan();
try {
const abortController = new AbortController();
setTimeout(() => abortController.abort(), 1);
await m(1000, {signal: abortController.signal});
t.fail('Expected to reject');
} catch (err) {
t.is(err.name, 'AbortError');
t.true(end() < 30);
}
const abortController = new AbortController();
setTimeout(() => abortController.abort(), 1);
await t.throwsAsync(
m(1000, {signal: abortController.signal}),
{name: 'AbortError'}
);
t.true(end() < 30);
});

test('resolution can be aborted with an AbortSignal if a value is passed', async t => {
const end = timeSpan();
try {
const abortController = new AbortController();
setTimeout(() => abortController.abort(), 1);
await m(1000, {value: 123, signal: abortController.signal});
t.fail('Expected to reject');
} catch (err) {
t.is(err.name, 'AbortError');
t.true(end() < 30);
}
const abortController = new AbortController();
setTimeout(() => abortController.abort(), 1);
await t.throwsAsync(
m(1000, {value: 123, signal: abortController.signal}),
{name: 'AbortError'}
);
t.true(end() < 30);
});

test('rejection can be aborted with an AbortSignal if a value is passed', async t => {
const end = timeSpan();
try {
const abortController = new AbortController();
setTimeout(() => abortController.abort(), 1);
await m.reject(1000, {value: new Error(), signal: abortController.signal});
t.fail('Expected to reject');
} catch (err) {
t.is(err.name, 'AbortError');
t.true(end() < 30);
}
const abortController = new AbortController();
setTimeout(() => abortController.abort(), 1);
await t.throwsAsync(
m.reject(1000, {value: new Error(), signal: abortController.signal}),
{name: 'AbortError'}
);
t.true(end() < 30);
});

test('rejects with AbortError if AbortSignal is already aborted', async t => {
const end = timeSpan();
try {
const abortController = new AbortController();
abortController.abort();
await m(1000, {signal: abortController.signal});
t.fail('Expected to reject');
} catch (err) {
t.is(err.name, 'AbortError');
t.true(end() < 30);
}
const abortController = new AbortController();
abortController.abort();
await t.throwsAsync(
m(1000, {signal: abortController.signal}),
{name: 'AbortError'}
);
t.true(end() < 30);
});

0 comments on commit f21bfc8

Please sign in to comment.