extends-promise
Advanced tools
Comparing version 1.0.0 to 1.1.0
50
index.js
@@ -22,6 +22,2 @@ "use strict"; | ||
delay(ms) { | ||
return this.then(res => new P(resolve => setTimeout(() => resolve(res), ms))); | ||
} | ||
tap(fn) { | ||
@@ -35,2 +31,12 @@ return this.then(res => { | ||
toCallback(cb) { | ||
return this | ||
.then(res => cb(null, res)) | ||
.catch(err => cb(err)); | ||
} | ||
delay(ms) { | ||
return this.then(res => new P(resolve => setTimeout(() => resolve(res), ms))); | ||
} | ||
map(fn) { | ||
@@ -48,2 +54,38 @@ return this.then(res => P.all(res.map(fn))); | ||
reduce(fn, initialValue) { | ||
const reducer = (y, x, i, a) => P.resolve(y).then(z => fn(z, x, i, a)); | ||
const args = arguments.length > 1 ? [reducer, initialValue] : [reducer]; | ||
return this.then(res => res.reduce.apply(res, args)); | ||
} | ||
forEach(fn) { | ||
return this | ||
.reduce((y, x, i, a) => fn(x, i, a), null) | ||
.return(undefined); | ||
} | ||
// Methods should also be available as static | ||
static delay(ms, val) { | ||
return P.resolve(val).delay(ms); | ||
} | ||
static map(val, fn) { | ||
return P.resolve(val).map(fn); | ||
} | ||
static filter(val, fn) { | ||
return P.resolve(val).filter(fn); | ||
} | ||
static reduce(val, fn, initialValue) { | ||
const p = P.resolve(val); | ||
return arguments.length > 2 ? p.reduce(fn, initialValue) : p.reduce(fn); | ||
} | ||
static forEach(val, fn) { | ||
return P.resolve(val).forEach(fn); | ||
} | ||
static promisify(fn, ctx) { | ||
@@ -50,0 +92,0 @@ return function promisifedMethod() { |
{ | ||
"name": "extends-promise", | ||
"version": "1.0.0", | ||
"version": "1.1.0", | ||
"description": "Micro-library that extends native promises", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -11,4 +11,6 @@ [![NPM version][npm-image]][npm-url] [![Build Status][travis-image]][travis-url] [![Coverage Status][coveralls-image]][coveralls-url] [![Dependency Status][depstat-image]][depstat-url] | ||
### Static Methods | ||
Additional examples are available in [tests](tests). | ||
### Static Helpers | ||
#### `promisify(Function fn, context)` | ||
@@ -120,3 +122,3 @@ | ||
Similar to `[].map` but waits for promises returned from the mapping function to resolve. NOTE: This will run all map functions concurrently. | ||
Similar to `[].map` but, waits for promises returned from the mapping function to resolve. NOTE: This will run all map functions concurrently. | ||
@@ -145,2 +147,44 @@ ```js | ||
#### `reduce(Function method[, initialValue])` | ||
Similar to `[].reduce` but, waits for each iteration to resolve before calling the next method. The callback method may return promises or values. The optional intialValue may also be a value, promise. | ||
```js | ||
const P = require("extends-promise"); | ||
P.resolve([2, 3, 4]) | ||
.reduce((y, x) => y + x, 1) | ||
.then(console.log); | ||
``` | ||
#### `forEach(Function method)` | ||
Similar to `[].forEach` but, accepts a method that returns a promise. Each iteration of the loop will run serially. | ||
```js | ||
const P = require("extends-promise"); | ||
P.resolve([1, 2, 3]) | ||
.forEach(console.log); | ||
``` | ||
#### `toCallback(Function callback)` | ||
Converts a promise back into callback style async. Uses error first convention. | ||
```js | ||
P.resolve(1) | ||
.toCallback((err, res) => console.log(res)); | ||
```` | ||
### Instance Short-hand Statics | ||
Each of the following instance methods are also available as static methods which accept a resolved value. | ||
* `delay(ms, value)` | ||
* `map(Array, Function)` | ||
* `filter(Array, Function)` | ||
* `reduce(Array, Function[, initialValue])` | ||
* `forEach(Array, Function)` | ||
## Contributing | ||
@@ -156,3 +200,3 @@ | ||
[MIT License](LICENSE.md) | ||
[MIT License](LICENSE) | ||
@@ -159,0 +203,0 @@ [npm-url]: https://npmjs.org/package/extends-promise |
@@ -11,29 +11,129 @@ "use strict"; | ||
describe("Functional", () => { | ||
it(".map: should map function resolved array", () => { | ||
return P | ||
.resolve([1, 2, 3]) | ||
.map(x => x * 10) | ||
.then(res => assert.deepEqual(res, [10, 20, 30])); | ||
describe(".map", () => { | ||
it("should map function resolved array", () => { | ||
return P | ||
.resolve([1, 2, 3]) | ||
.map(x => x * 10) | ||
.then(res => assert.deepEqual(res, [10, 20, 30])); | ||
}); | ||
it("should wait for mapped promises to resolve", () => { | ||
return P | ||
.resolve([1]) | ||
.map(x => P.resolve(x * 10)) | ||
.then(res => assert.deepEqual(res, [10])); | ||
}); | ||
it("should be available as a static method", () => { | ||
return P | ||
.map([1, 2, 3], x => x * 10) | ||
.then(res => assert.deepEqual(res, [10, 20, 30])); | ||
}); | ||
}); | ||
it(".map: should wait for mapped promises to resolve", () => { | ||
return P | ||
.resolve([1]) | ||
.map(x => P.resolve(x * 10)) | ||
.then(res => assert.deepEqual(res, [10])); | ||
describe(".filter", () => { | ||
it("should filter resolved array", () => { | ||
return P | ||
.resolve([1, 2, 3, 4]) | ||
.filter(x => x % 2) | ||
.then(res => assert.deepEqual(res, [1, 3])); | ||
}); | ||
it("should wait for async filter methods", () => { | ||
return P | ||
.resolve([1, 2, 3, 4]) | ||
.filter(x => P.resolve(x % 2)) | ||
.then(res => assert.deepEqual(res, [1, 3])); | ||
}); | ||
it("should be available as a static method", () => { | ||
return P | ||
.filter([1, 2, 3, 4], x => x % 2) | ||
.then(res => assert.deepEqual(res, [1, 3])); | ||
}); | ||
}); | ||
it(".filter: should filter resolved array", () => { | ||
return P | ||
.resolve([1, 2, 3, 4]) | ||
.filter(x => x % 2) | ||
.then(res => assert.deepEqual(res, [1, 3])); | ||
describe(".reduce", () => { | ||
it("should take initial value", () => { | ||
return P | ||
.resolve([2, 3, 4]) | ||
.reduce((y, x) => y + x, 1) | ||
.then(res => assert.strictEqual(res, 10)); | ||
}); | ||
it("should use first value as initial value when not provided", () => { | ||
return P | ||
.resolve([1, 2, 3, 4]) | ||
.reduce((y, x) => y + x) | ||
.then(res => assert.strictEqual(res, 10)); | ||
}); | ||
it("should include same arguments as Array#reduce", () => { | ||
return P | ||
.resolve([2]) | ||
.reduce((y, x, i, arr) => { | ||
assert.strictEqual(y, 1); | ||
assert.strictEqual(x, 2); | ||
assert.strictEqual(i, 0); | ||
assert.deepEqual(arr, [2]); | ||
}, 1); | ||
}); | ||
it("should accept promise returning reducer and initial value", () => { | ||
return P | ||
.resolve([2, 3, 4]) | ||
.map(x => P.resolve(x)) | ||
.reduce((y, x) => y + x, P.resolve(1)) | ||
.then(res => assert.strictEqual(res, 10)); | ||
}); | ||
it("should be available as a static method with initial value", () => { | ||
return P | ||
.reduce([2, 3, 4], (y, x) => y + x, 1) | ||
.then(res => assert.strictEqual(res, 10)); | ||
}); | ||
it("should be available as a static method without initial value", () => { | ||
return P | ||
.reduce([1, 2, 3, 4], (y, x) => y + x) | ||
.then(res => assert.strictEqual(res, 10)); | ||
}); | ||
}); | ||
it(".filter: should wait for async filter methods", () => { | ||
return P | ||
.resolve([1, 2, 3, 4]) | ||
.filter(x => P.resolve(x % 2)) | ||
.then(res => assert.deepEqual(res, [1, 3])); | ||
describe(".forEach", () => { | ||
it("should call method for each element in array", () => { | ||
const res = []; | ||
return P | ||
.resolve([1, 2, 3]) | ||
.forEach(x => res.push(x)) | ||
.then(() => assert.deepEqual(res, [1, 2, 3])); | ||
}); | ||
it("should always return undefined", () => { | ||
return P | ||
.resolve([1, 2, 3]) | ||
.forEach(x => x) | ||
.then(res => assert.strictEqual(res, undefined)); | ||
}); | ||
it("should run each iteration serially", () => { | ||
let ran = false; | ||
return P | ||
.resolve([1, 2]) | ||
.forEach((x, i) => { | ||
switch (i) { | ||
case 0: return P.delay(10).then(() => ran = true); | ||
case 1: return assert.strictEqual(ran, true); | ||
default: throw new Error('forEach was called more times than expected.'); | ||
} | ||
}); | ||
}); | ||
it("should be available as a static method", () => { | ||
return P | ||
.forEach([0, 1, 2], (x, i) => assert.strictEqual(x, i)); | ||
}); | ||
}); | ||
}); |
@@ -11,66 +11,78 @@ "use strict"; | ||
describe("Helpers", () => { | ||
it(".return: should be able to return value", () => { | ||
return P | ||
.resolve(1) | ||
.return(2) | ||
.then(res => assert.strictEqual(res, 2)); | ||
describe(".return", () => { | ||
it("should be able to return value", () => { | ||
return P | ||
.resolve(1) | ||
.return(2) | ||
.then(res => assert.strictEqual(res, 2)); | ||
}); | ||
}); | ||
it(".call: should be able to invoke a method", () => { | ||
return P | ||
.resolve(1) | ||
.call("toString") | ||
.then(res => assert.strictEqual(res, "1")); | ||
}); | ||
describe(".call", () => { | ||
it("should be able to invoke a method", () => { | ||
return P | ||
.resolve(1) | ||
.call("toString") | ||
.then(res => assert.strictEqual(res, "1")); | ||
}); | ||
it(".call: should be able to invoke a method with arguments", () => { | ||
return P | ||
.resolve(10) | ||
.call("toString", 16) | ||
.then(res => assert.strictEqual(res, "a")); | ||
it("should be able to invoke a method with arguments", () => { | ||
return P | ||
.resolve(10) | ||
.call("toString", 16) | ||
.then(res => assert.strictEqual(res, "a")); | ||
}); | ||
}); | ||
// TODO: Find a way to use sinon.js fake timers | ||
// https://github.com/sinonjs/sinon/issues/738 | ||
it(".delay: should defer resolution of promise", () => { | ||
let res = null; | ||
describe(".delay", () => { | ||
it("should defer resolution of promise", () => { | ||
let res = null; | ||
P.resolve(1) | ||
.delay(10) | ||
.then(x => res = x); | ||
P.resolve(1) | ||
.delay(10) | ||
.then(x => res = x); | ||
return P | ||
.resolve() | ||
.then(() => assert.strictEqual(res, null)) | ||
.delay(20) | ||
.then(() => assert.strictEqual(res, 1)); | ||
}); | ||
return P | ||
.resolve() | ||
.then(() => assert.strictEqual(res, null)) | ||
.delay(20) | ||
.then(() => assert.strictEqual(res, 1)); | ||
}); | ||
it(".delay: should resolve value", () => { | ||
return P | ||
.resolve(1) | ||
.delay(1) | ||
.then(res => assert.strictEqual(res, 1)); | ||
}); | ||
it("should resolve value", () => { | ||
return P | ||
.resolve(1) | ||
.delay(1) | ||
.then(res => assert.strictEqual(res, 1)); | ||
}); | ||
it(".tap: should be able to call then without affecting chain", () => { | ||
return P | ||
.resolve(1) | ||
.tap(() => 2) | ||
.then(res => assert.strictEqual(res, 1)); | ||
it("should be available as static method", () => { | ||
return P | ||
.delay(1, 5) | ||
.then(res => assert.strictEqual(res, 5)); | ||
}); | ||
}); | ||
it(".tap: should wait for returned promise to resolve", () => { | ||
let waited = false; | ||
describe(".tap", () => { | ||
it(".tap: should be able to call then without affecting chain", () => { | ||
return P | ||
.resolve(1) | ||
.tap(() => 2) | ||
.then(res => assert.strictEqual(res, 1)); | ||
}); | ||
return P | ||
.resolve(1) | ||
.tap(() => { | ||
return P | ||
.resolve(1) | ||
.delay(1) | ||
.then(() => waited = true); | ||
}) | ||
.then(() => assert.strictEqual(waited, true)); | ||
it(".tap: should wait for returned promise to resolve", () => { | ||
let waited = false; | ||
return P | ||
.resolve(1) | ||
.tap(() => { | ||
return P | ||
.resolve(1) | ||
.delay(1) | ||
.then(() => waited = true); | ||
}) | ||
.then(() => assert.strictEqual(waited, true)); | ||
}); | ||
}); | ||
}); |
@@ -11,75 +11,109 @@ "use strict"; | ||
describe("Promise", () => { | ||
it(".then: should be able to use as promise", () => { | ||
return new P(resolve => resolve()) | ||
.then(() => P.resolve(1)) | ||
.then(res => assert.strictEqual(res, 1)); | ||
describe(".then", () => { | ||
it("should be able to use as promise", () => { | ||
return new P(resolve => resolve()) | ||
.then(() => P.resolve(1)) | ||
.then(res => assert.strictEqual(res, 1)); | ||
}); | ||
}); | ||
it(".promisify: should be able to promisify callback method", () => { | ||
const fn = P.promisify((x, cb) => cb(null, x)); | ||
describe(".promisify", () => { | ||
it("should be able to promisify callback method", () => { | ||
const fn = P.promisify((x, cb) => cb(null, x)); | ||
return fn(1) | ||
.then(res => assert.strictEqual(res, 1)); | ||
}); | ||
return fn(1) | ||
.then(res => assert.strictEqual(res, 1)); | ||
}); | ||
it(".promisify: should reject callback method with error", () => { | ||
const fn = P.promisify(cb => cb(new Error("Callback error"))); | ||
it("should reject callback method with error", () => { | ||
const fn = P.promisify(cb => cb(new Error("Callback error"))); | ||
return fn() | ||
.then(() => Promise.reject(new Error("Did not reject"))) | ||
.catch(err => assert.strictEqual(err.message, "Callback error")); | ||
}); | ||
return fn() | ||
.then(() => Promise.reject(new Error("Did not reject"))) | ||
.catch(err => assert.strictEqual(err.message, "Callback error")); | ||
}); | ||
it(".promisify: should convert multiple arguments in callback to array", () => { | ||
const fn = P.promisify((x, y, cb) => cb(null, x, y)); | ||
it("should convert multiple arguments in callback to array", () => { | ||
const fn = P.promisify((x, y, cb) => cb(null, x, y)); | ||
return fn(1, 2) | ||
.then(res => assert.deepEqual(res, [1, 2])); | ||
}); | ||
return fn(1, 2) | ||
.then(res => assert.deepEqual(res, [1, 2])); | ||
}); | ||
it(".promisify: should be able to pass context to promisify", () => { | ||
const fn = P.promisify(function callbackMethod(cb) { | ||
cb(null, this); | ||
}, 1); | ||
it("should be able to pass context to promisify", () => { | ||
const fn = P.promisify(function callbackMethod(cb) { | ||
cb(null, this); | ||
}, 1); | ||
return fn() | ||
.then(res => assert.strictEqual(res, 1)); | ||
}); | ||
return fn() | ||
.then(res => assert.strictEqual(res, 1)); | ||
}); | ||
it(".promisify: should use dynamic context if not specified", () => { | ||
const o = { | ||
fn : P.promisify(function callbackMethod(cb) { | ||
cb(null, this); | ||
}) | ||
}; | ||
it("should use dynamic context if not specified", () => { | ||
const o = { | ||
fn : P.promisify(function callbackMethod(cb) { | ||
cb(null, this); | ||
}) | ||
}; | ||
return o.fn() | ||
.then(res => assert.strictEqual(res, o)); | ||
return o.fn() | ||
.then(res => assert.strictEqual(res, o)); | ||
}); | ||
}); | ||
it(".fromCallback: should be able to use fromCallback to promisify", () => { | ||
return P | ||
.fromCallback(cb => cb(null, 1)) | ||
.then(res => assert.strictEqual(res, 1)); | ||
describe(".fromCallback", () => { | ||
it("should be able to use fromCallback to promisify", () => { | ||
return P | ||
.fromCallback(cb => cb(null, 1)) | ||
.then(res => assert.strictEqual(res, 1)); | ||
}); | ||
it("should reject fromCallback with error", () => { | ||
return P | ||
.fromCallback(cb => cb(new Error("Callback error"))) | ||
.then(() => Promise.reject(new Error("Did not reject"))) | ||
.catch(err => assert.strictEqual(err.message, "Callback error")); | ||
}); | ||
}); | ||
it(".fromCallback: should reject fromCallback with error", () => { | ||
return P | ||
.fromCallback(cb => cb(new Error("Callback error"))) | ||
.then(() => Promise.reject(new Error("Did not reject"))) | ||
.catch(err => assert.strictEqual(err.message, "Callback error")); | ||
describe(".toCallback", () => { | ||
it("should be able to convert resolved promise to callback", cb => { | ||
return P | ||
.resolve(1) | ||
.toCallback((err, res) => { | ||
assert.strictEqual(err, null); | ||
assert.strictEqual(res, 1); | ||
cb(); | ||
}); | ||
}); | ||
it("should be able to convert rejected promise to callback", cb => { | ||
const testErr = new Error("Test error"); | ||
return P | ||
.reject(testErr) | ||
.toCallback((err, res) => { | ||
assert.strictEqual(err, testErr); | ||
assert.strictEqual(res, undefined); | ||
cb(); | ||
}); | ||
}); | ||
}); | ||
it(".extend: should be able to extend existing Promise implementation", () => { | ||
class APromise extends Promise {} | ||
describe(".extend", () => { | ||
it("should be able to extend existing Promise implementation", () => { | ||
class APromise extends Promise {} | ||
assert.strictEqual(P.extend(APromise), APromise); | ||
assert.strictEqual(APromise.promisify, P.promisify); | ||
assert.strictEqual(P.extend(APromise), APromise); | ||
assert.strictEqual(APromise.promisify, P.promisify); | ||
return APromise | ||
.resolve() | ||
.return(1) | ||
.tap(res => assert.strictEqual(res, 1)) | ||
.then(res => assert.strictEqual(res, 1)); | ||
return APromise | ||
.resolve() | ||
.return(1) | ||
.tap(res => assert.strictEqual(res, 1)) | ||
.then(res => assert.strictEqual(res, 1)); | ||
}); | ||
}); | ||
}); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
20273
468
210