Comparing version 0.2.0 to 0.2.1
@@ -22,3 +22,6 @@ /** | ||
this._reject = null; | ||
this._isResolved = true; | ||
// it seems that isPending can be calculated as `Boolean(this._promise) && !this.isFulfilled`, | ||
// but it is not true: if call(fn) throws error in the same tick, `this._promise` is yet undefined. | ||
this._isPending = false; | ||
this._isResolved = false; | ||
this._isRejected = false; | ||
@@ -42,4 +45,7 @@ this._promise = null; | ||
/** | ||
* Calls `fn`, returns new promise and holds `resolve` / `reject` callbacks. | ||
* If `timeout` specified, the promise will be rejected after `timeout` with `PendingTimeoutError`. | ||
* For the first time this method calls `fn` and returns new promise. Also holds `resolve` / `reject` callbacks | ||
* to allow fulfill promise via `pending.resolve()` and `pending.reject()`. All subsequent calls of `.call(fn)` | ||
* will return the same promise, which can be still pending or already fulfilled. | ||
* To reset this behavior use `.reset()`. If `timeout` is specified, the promise will be automatically rejected | ||
* after `timeout` milliseconds with `PendingTimeoutError`. | ||
* | ||
@@ -51,7 +57,9 @@ * @param {Function} fn | ||
value: function call(fn, timeout) { | ||
if (this.isFulfilled) { | ||
this._reset(); | ||
if (this._isPending || this.isFulfilled) { | ||
return this._promise; | ||
} else { | ||
this.reset(); | ||
this._createPromise(fn, timeout); | ||
return this._promise; | ||
} | ||
return this._promise; | ||
} | ||
@@ -68,3 +76,4 @@ | ||
value: function resolve(value) { | ||
if (!this.isFulfilled) { | ||
if (this._isPending) { | ||
this._isPending = false; | ||
this._isResolved = true; | ||
@@ -86,3 +95,4 @@ this._clearTimer(); | ||
value: function reject(reason) { | ||
if (!this.isFulfilled) { | ||
if (this._isPending) { | ||
this._isPending = false; | ||
this._isRejected = true; | ||
@@ -96,3 +106,3 @@ this._clearTimer(); | ||
/** | ||
* Rejects if `reason` is truthy, otherwise resolves with `value`. | ||
* Helper method: rejects if `reason` is truthy, otherwise resolves with `value`. | ||
* | ||
@@ -112,3 +122,20 @@ * @param {*} [value] | ||
} | ||
/** | ||
* Resets to initial state. | ||
*/ | ||
}, { | ||
key: 'reset', | ||
value: function reset() { | ||
if (this._isPending) { | ||
this.reject(new Error('Pending reset')); | ||
} | ||
this._promise = null; | ||
this._isPending = false; | ||
this._isResolved = false; | ||
this._isRejected = false; | ||
this._clearTimer(); | ||
} | ||
}, { | ||
key: '_createPromise', | ||
@@ -127,2 +154,3 @@ value: function _createPromise(fn, timeout) { | ||
this._promise = new Promise(function (resolve, reject) { | ||
_this._isPending = true; | ||
_this._resolve = resolve; | ||
@@ -162,8 +190,2 @@ _this._reject = reject; | ||
}, { | ||
key: '_reset', | ||
value: function _reset() { | ||
this._isResolved = false; | ||
this._isRejected = false; | ||
} | ||
}, { | ||
key: 'promise', | ||
@@ -170,0 +192,0 @@ get: function get() { |
@@ -15,3 +15,3 @@ /** | ||
/** | ||
* Creates list of pending promises. | ||
* Creates dynamic list of promises. When each promise if fulfilled it is remove from list. | ||
* | ||
@@ -18,0 +18,0 @@ * @param {Object} [options] |
{ | ||
"name": "pendings", | ||
"version": "0.2.0", | ||
"version": "0.2.1", | ||
"description": "Better control of pending promises", | ||
@@ -5,0 +5,0 @@ "author": { |
@@ -17,8 +17,16 @@ # Pendings | ||
## Usage | ||
When using promises in event-based code we need to manually store `resolve` / `reject` callbacks: | ||
## Usage (single promise) | ||
Typical situation with promises in event-based code: | ||
```js | ||
class Foo { | ||
asyncRequest() { | ||
return new Promise((resolve, reject) => { | ||
constructor() { | ||
this.promise = null; | ||
this.resolve = null; | ||
this.reject = null; | ||
} | ||
asyncRequest() { | ||
if (this.promise) { // if promise already exists - return it | ||
return this.promise; | ||
} | ||
this.promise = new Promise((resolve, reject) => { | ||
this.resolve = resolve; | ||
@@ -28,12 +36,10 @@ this.reject = reject; | ||
}); | ||
return this.promise; | ||
} | ||
} | ||
``` | ||
and resolve later: | ||
```js | ||
onSuccess(data) { | ||
this.resolve(data); | ||
} | ||
} | ||
``` | ||
*Pendings* allows to do it simpler: | ||
[Pending](#Pending) class allows to do it simpler: | ||
```js | ||
@@ -49,13 +55,11 @@ const Pending = require('pendings').Pending; | ||
} | ||
} | ||
``` | ||
and resolve later: | ||
```js | ||
onSuccess(data) { | ||
this.pending.resolve(data); | ||
} | ||
} | ||
``` | ||
This is even more useful for list of promises. | ||
Each promise automatically gets unique `id` that allows to fulfill it later: | ||
## Usage (list of promises) | ||
[Pendings](#Pendings) class is useful for dynamic list of promises. | ||
Each promise can automatically get unique `id` and can be fulfilled later by that id. | ||
After fulfillment promise is removed from list. | ||
```js | ||
@@ -76,7 +80,7 @@ const Pendings = require('pendings'); | ||
onSuccess(data) { | ||
this.pendings.resolve(data.id, data); // resolve by `id` property of event | ||
this.pendings.resolve(data.id, data); // resolve by `id` | ||
} | ||
onError(data) { | ||
this.pendings.reject(data.id, data); // reject by `id` property of event | ||
this.pendings.reject(data.id, data); // reject by `id` | ||
} | ||
@@ -83,0 +87,0 @@ } |
@@ -17,8 +17,16 @@ # Pendings | ||
## Usage | ||
When using promises in event-based code we need to manually store `resolve` / `reject` callbacks: | ||
## Usage (single promise) | ||
Typical situation with promises in event-based code: | ||
```js | ||
class Foo { | ||
asyncRequest() { | ||
return new Promise((resolve, reject) => { | ||
constructor() { | ||
this.promise = null; | ||
this.resolve = null; | ||
this.reject = null; | ||
} | ||
asyncRequest() { | ||
if (this.promise) { // if promise already exists - return it | ||
return this.promise; | ||
} | ||
this.promise = new Promise((resolve, reject) => { | ||
this.resolve = resolve; | ||
@@ -28,12 +36,10 @@ this.reject = reject; | ||
}); | ||
return this.promise; | ||
} | ||
} | ||
``` | ||
and resolve later: | ||
```js | ||
onSuccess(data) { | ||
this.resolve(data); | ||
} | ||
} | ||
``` | ||
*Pendings* allows to do it simpler: | ||
[Pending](#Pending) class allows to do it simpler: | ||
```js | ||
@@ -49,13 +55,11 @@ const Pending = require('pendings').Pending; | ||
} | ||
} | ||
``` | ||
and resolve later: | ||
```js | ||
onSuccess(data) { | ||
this.pending.resolve(data); | ||
} | ||
} | ||
``` | ||
This is even more useful for list of promises. | ||
Each promise automatically gets unique `id` that allows to fulfill it later: | ||
## Usage (list of promises) | ||
[Pendings](#Pendings) class is useful for dynamic list of promises. | ||
Each promise can automatically get unique `id` and can be fulfilled later by that id. | ||
After fulfillment promise is removed from list. | ||
```js | ||
@@ -76,7 +80,7 @@ const Pendings = require('pendings'); | ||
onSuccess(data) { | ||
this.pendings.resolve(data.id, data); // resolve by `id` property of event | ||
this.pendings.resolve(data.id, data); // resolve by `id` | ||
} | ||
onError(data) { | ||
this.pendings.reject(data.id, data); // reject by `id` property of event | ||
this.pendings.reject(data.id, data); // reject by `id` | ||
} | ||
@@ -115,2 +119,3 @@ } | ||
* [.fulfill([value], [reason])](#Pending+fulfill) | ||
* [.reset()](#Pending+reset) | ||
@@ -160,4 +165,7 @@ <a name="new_Pending_new"></a> | ||
### pending.call(fn, [timeout]) ⇒ <code>Promise</code> | ||
Calls `fn`, returns new promise and holds `resolve` / `reject` callbacks. | ||
If `timeout` specified, the promise will be rejected after `timeout` with `PendingTimeoutError`. | ||
For the first time this method calls `fn` and returns new promise. Also holds `resolve` / `reject` callbacks | ||
to allow fulfill promise via `pending.resolve()` and `pending.reject()`. All subsequent calls of `.call(fn)` | ||
will return the same promise, which can be still pending or already fulfilled. | ||
To reset this behavior use `.reset()`. If `timeout` is specified, the promise will be automatically rejected | ||
after `timeout` milliseconds with `PendingTimeoutError`. | ||
@@ -196,3 +204,3 @@ **Kind**: instance method of [<code>Pending</code>](#Pending) | ||
### pending.fulfill([value], [reason]) | ||
Rejects if `reason` is truthy, otherwise resolves with `value`. | ||
Helper method: rejects if `reason` is truthy, otherwise resolves with `value`. | ||
@@ -206,2 +214,8 @@ **Kind**: instance method of [<code>Pending</code>](#Pending) | ||
<a name="Pending+reset"></a> | ||
### pending.reset() | ||
Resets to initial state. | ||
**Kind**: instance method of [<code>Pending</code>](#Pending) | ||
<a name="Pendings"></a> | ||
@@ -229,3 +243,3 @@ | ||
### new Pendings([options]) | ||
Creates list of pending promises. | ||
Creates dynamic list of promises. When each promise if fulfilled it is remove from list. | ||
@@ -232,0 +246,0 @@ |
@@ -16,3 +16,6 @@ /** | ||
this._reject = null; | ||
this._isResolved = true; | ||
// it seems that isPending can be calculated as `Boolean(this._promise) && !this.isFulfilled`, | ||
// but it is not true: if call(fn) throws error in the same tick, `this._promise` is yet undefined. | ||
this._isPending = false; | ||
this._isResolved = false; | ||
this._isRejected = false; | ||
@@ -74,4 +77,7 @@ this._promise = null; | ||
/** | ||
* Calls `fn`, returns new promise and holds `resolve` / `reject` callbacks. | ||
* If `timeout` specified, the promise will be rejected after `timeout` with `PendingTimeoutError`. | ||
* For the first time this method calls `fn` and returns new promise. Also holds `resolve` / `reject` callbacks | ||
* to allow fulfill promise via `pending.resolve()` and `pending.reject()`. All subsequent calls of `.call(fn)` | ||
* will return the same promise, which can be still pending or already fulfilled. | ||
* To reset this behavior use `.reset()`. If `timeout` is specified, the promise will be automatically rejected | ||
* after `timeout` milliseconds with `PendingTimeoutError`. | ||
* | ||
@@ -83,7 +89,9 @@ * @param {Function} fn | ||
call(fn, timeout) { | ||
if (this.isFulfilled) { | ||
this._reset(); | ||
if (this._isPending || this.isFulfilled) { | ||
return this._promise; | ||
} else { | ||
this.reset(); | ||
this._createPromise(fn, timeout); | ||
return this._promise; | ||
} | ||
return this._promise; | ||
} | ||
@@ -97,3 +105,4 @@ | ||
resolve(value) { | ||
if (!this.isFulfilled) { | ||
if (this._isPending) { | ||
this._isPending = false; | ||
this._isResolved = true; | ||
@@ -112,3 +121,4 @@ this._clearTimer(); | ||
reject(reason) { | ||
if (!this.isFulfilled) { | ||
if (this._isPending) { | ||
this._isPending = false; | ||
this._isRejected = true; | ||
@@ -122,3 +132,3 @@ this._clearTimer(); | ||
/** | ||
* Rejects if `reason` is truthy, otherwise resolves with `value`. | ||
* Helper method: rejects if `reason` is truthy, otherwise resolves with `value`. | ||
* | ||
@@ -136,2 +146,16 @@ * @param {*} [value] | ||
/** | ||
* Resets to initial state. | ||
*/ | ||
reset() { | ||
if (this._isPending) { | ||
this.reject(new Error('Pending reset')); | ||
} | ||
this._promise = null; | ||
this._isPending = false; | ||
this._isResolved = false; | ||
this._isRejected = false; | ||
this._clearTimer(); | ||
} | ||
_createPromise(fn, timeout) { | ||
@@ -146,2 +170,3 @@ this._initPromise(fn); | ||
this._promise = new Promise((resolve, reject) => { | ||
this._isPending = true; | ||
this._resolve = resolve; | ||
@@ -173,9 +198,4 @@ this._reject = reject; | ||
} | ||
_reset() { | ||
this._isResolved = false; | ||
this._isRejected = false; | ||
} | ||
} | ||
module.exports = Pending; |
@@ -11,3 +11,3 @@ /** | ||
/** | ||
* Creates list of pending promises. | ||
* Creates dynamic list of promises. When each promise if fulfilled it is remove from list. | ||
* | ||
@@ -14,0 +14,0 @@ * @param {Object} [options] |
@@ -36,9 +36,25 @@ 'use strict'; | ||
it('should return new promise for second call if previous was fulfilled', function () { | ||
it('should return the same promise for second call if previous was fulfilled', function () { | ||
const p1 = this.pending.call(noop); | ||
this.pending.resolve(); | ||
const p2 = this.pending.call(noop); | ||
assert.equal(p1, p2); | ||
}); | ||
it('should return new promise for second call after resolve + reset', function () { | ||
const p1 = this.pending.call(noop); | ||
this.pending.resolve(); | ||
this.pending.reset(); | ||
const p2 = this.pending.call(noop); | ||
assert.notEqual(p1, p2); | ||
}); | ||
it('should return new promise for second call after reject + reset', function () { | ||
const p1 = this.pending.call(noop); | ||
this.pending.reject(); | ||
this.pending.reset(); | ||
const p2 = this.pending.call(noop); | ||
assert.notEqual(p1, p2); | ||
}); | ||
it('should allow to call without fn', function () { | ||
@@ -64,2 +80,6 @@ const res = this.pending.call(); | ||
}); | ||
it('should do nothing for resolve without call', function () { | ||
assert.doesNotThrow(() => this.pending.resolve('foo')); | ||
}); | ||
}); | ||
@@ -87,2 +107,6 @@ | ||
}); | ||
it('should do nothing for reject without call', function () { | ||
assert.doesNotThrow(() => this.pending.reject('foo')); | ||
}); | ||
}); | ||
@@ -113,3 +137,3 @@ | ||
it('should set after resolve', function () { | ||
assert.ok(this.pending.isFulfilled); | ||
assert.notOk(this.pending.isFulfilled); | ||
this.pending.call(); | ||
@@ -121,4 +145,4 @@ assert.notOk(this.pending.isFulfilled); | ||
it('should set after reject', function () { | ||
assert.ok(this.pending.isFulfilled); | ||
it('should set after manual reject', function () { | ||
assert.notOk(this.pending.isFulfilled); | ||
const res = this.pending.call(); | ||
@@ -131,4 +155,4 @@ assert.notOk(this.pending.isFulfilled); | ||
it('should set after reject (by error in fn)', function () { | ||
assert.ok(this.pending.isFulfilled); | ||
it('should set after reject by error in fn', function () { | ||
assert.notOk(this.pending.isFulfilled); | ||
const res = this.pending.call(() => { | ||
@@ -167,2 +191,17 @@ throw new Error('err'); | ||
describe('reset', function () { | ||
it('should reset resolved promise', function () { | ||
this.pending.call(); | ||
this.pending.resolve(); | ||
this.pending.reset(); | ||
assert.equal(this.pending.isResolved, false); | ||
}); | ||
it('should reject pending promise', function () { | ||
const res = this.pending.call(noop); | ||
this.pending.reset(); | ||
return assert.isRejected(res, 'Pending reset'); | ||
}); | ||
}); | ||
describe('timeout', function () { | ||
@@ -169,0 +208,0 @@ it('should resolve before timeout', function () { |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
52922
1203
394
0