Comparing version 0.3.0 to 0.4.0
@@ -6,3 +6,3 @@ { | ||
"authors": ["Paul Mucur"], | ||
"version": "0.3.0", | ||
"version": "0.4.0", | ||
"main": "lib/pacta.js", | ||
@@ -9,0 +9,0 @@ "devDependencies": { |
@@ -19,3 +19,3 @@ /* A simple demonstration of using Pacta to compose asynchronous HTTP requests. | ||
var http = require('./promised-http'), | ||
Promise = require('../lib/pacta').Promise; | ||
Promise = require('../lib/pacta'); | ||
@@ -22,0 +22,0 @@ var random = function (coll) { |
var http = require('http'), | ||
Promise = require('../lib/pacta').Promise; | ||
Promise = require('../lib/pacta'); | ||
@@ -4,0 +4,0 @@ var get = function (options) { |
111
lib/pacta.js
@@ -15,3 +15,3 @@ /*global module, define, process, setImmediate, setTimeout */ | ||
var nextTick, indexOf, EventEmitter, Promise, thenable, reduce; | ||
var nextTick, indexOf, EventEmitter, Promise, reduce; | ||
@@ -177,7 +177,17 @@ if (typeof Array.prototype.reduce !== 'function') { | ||
nextTick(function () { | ||
promise.resolve(f(reason)); | ||
try { | ||
promise.resolve(f(reason)); | ||
} catch (e) { | ||
promise.reject(e); | ||
} | ||
}); | ||
} else { | ||
this.emitter.once('rejected', function (reason) { | ||
promise.resolve(f(reason)); | ||
nextTick(function () { | ||
try { | ||
promise.resolve(f(reason)); | ||
} catch (e) { | ||
promise.reject(e); | ||
} | ||
}); | ||
}); | ||
@@ -196,7 +206,17 @@ } | ||
nextTick(function () { | ||
promise.resolve(f(value)); | ||
try { | ||
promise.resolve(f(value)); | ||
} catch (e) { | ||
promise.reject(e); | ||
} | ||
}); | ||
} else { | ||
this.emitter.once('resolved', function (x) { | ||
promise.resolve(f(x)); | ||
nextTick(function () { | ||
try { | ||
promise.resolve(f(x)); | ||
} catch (e) { | ||
promise.reject(e); | ||
} | ||
}); | ||
}); | ||
@@ -293,8 +313,2 @@ } | ||
/* Determine whether a value is "thenable" in Promises/A+ terminology. */ | ||
thenable = function (x) { | ||
return x !== null && typeof x === 'object' && | ||
typeof x.then === 'function'; | ||
}; | ||
/* Compatibility with the Promises/A+ specification. */ | ||
@@ -308,12 +322,3 @@ Promise.prototype.then = function (onFulfilled, onRejected) { | ||
var value = onFulfilled(x); | ||
if (thenable(value)) { | ||
value.then(function (x) { | ||
promise.resolve(x); | ||
}, function (reason) { | ||
promise.reject(reason); | ||
}); | ||
} else { | ||
promise.resolve(value); | ||
} | ||
Promise.resolve(promise, value); | ||
} catch (e) { | ||
@@ -332,13 +337,4 @@ promise.reject(e); | ||
try { | ||
reason = onRejected(reason); | ||
if (thenable(reason)) { | ||
reason.then(function (x) { | ||
promise.resolve(x); | ||
}, function (reason) { | ||
promise.reject(reason); | ||
}); | ||
} else { | ||
promise.resolve(reason); | ||
} | ||
var x = onRejected(reason); | ||
Promise.resolve(promise, x); | ||
} catch (e) { | ||
@@ -357,2 +353,53 @@ promise.reject(e); | ||
/* The Promises/A+ Resolution Procedure. | ||
* c.f. http://promisesaplus.com/#the_promise_resolution_procedure | ||
*/ | ||
Promise.resolve = function (promise, x) { | ||
var then, called = false; | ||
if (promise === x) { | ||
/* 2.3.1. */ | ||
promise.reject(new TypeError('Promises/A+ 2.3.1. If promise and ' + | ||
'x refer to the same object, reject ' + | ||
'promise with a TypeError as the ' + | ||
'reason.')); | ||
} else if (x !== null && | ||
(typeof x === 'object' || typeof x === 'function')) { | ||
/* 2.3.3. */ | ||
try { | ||
then = x.then; | ||
if (typeof then === 'function') { | ||
try { | ||
/* 2.3.3.3. */ | ||
then.call(x, function (y) { | ||
if (!called) { | ||
Promise.resolve(promise, y); | ||
called = true; | ||
} | ||
}, function (r) { | ||
if (!called) { | ||
promise.reject(r); | ||
called = true; | ||
} | ||
}); | ||
} catch (e) { | ||
if (!called) { | ||
promise.reject(e); | ||
} | ||
} | ||
} else { | ||
promise.resolve(x); | ||
} | ||
} catch (e) { | ||
promise.reject(e); | ||
} | ||
} else { | ||
promise.resolve(x); | ||
} | ||
}; | ||
/* of :: a -> Promise a */ | ||
@@ -359,0 +406,0 @@ Promise.of = function (x) { |
@@ -7,8 +7,8 @@ { | ||
"keywords": ["promises", "monad", "functor", "promises-aplus"], | ||
"version": "0.3.0", | ||
"version": "0.4.0", | ||
"main": "./lib/pacta.js", | ||
"dependencies": {}, | ||
"devDependencies": { | ||
"mocha": "1.10.0", | ||
"promises-aplus-tests": "1.3.1" | ||
"mocha": "1.16.1", | ||
"promises-aplus-tests": "2.0.3" | ||
}, | ||
@@ -15,0 +15,0 @@ "scripts": { "test": "mocha" }, |
# pacta [![Build Status](https://travis-ci.org/mudge/pacta.png?branch=master)](https://travis-ci.org/mudge/pacta) | ||
```javascript | ||
{ 'pacta': '0.3.0' } | ||
{ 'pacta': '0.4.0' } | ||
``` | ||
@@ -252,2 +252,5 @@ | ||
Note that any uncaught exceptions during the execution of `f` will result in | ||
the promise being `rejected` with the exception as its `reason`. | ||
### `Promise#then([onFulfilled[, onRejected]])` | ||
@@ -272,3 +275,3 @@ | ||
An implementation of the [Promises/A+ `then` | ||
method](http://promises-aplus.github.io/promises-spec/#the__method), taking an | ||
method](http://promisesaplus.com/#the__method), taking an | ||
optional `onFulfilled` and `onRejected` function to call when the promise is | ||
@@ -293,2 +296,28 @@ fulfilled or rejected respectively. | ||
Note that `onRejected` returns a promise itself that is fulfilled by the given | ||
function, `f`. In this way, you can gracefully recover from errors like so: | ||
```javascript | ||
var p = new Promise(); | ||
p.reject('Error!'); | ||
p.onRejected(function (reason) { | ||
return 'Some safe default'; | ||
}).map(console.log); | ||
//=> Logs "Some safe default" | ||
``` | ||
Like [`Promise#map`](#promisemapf), any uncaught exceptions within `f` will | ||
result in a `rejected` promise: | ||
```javascript | ||
var p = new Promise(); | ||
p.reject('Error!'); | ||
p.onRejected(function (reason) { | ||
throw 'Another error!'; | ||
}).onRejected(console.log); | ||
//=> Logs "Another error!" | ||
``` | ||
### `Promise#concat(p)` | ||
@@ -295,0 +324,0 @@ |
@@ -17,6 +17,6 @@ 'use strict'; | ||
exports.pending = function () { | ||
exports.deferred = function () { | ||
return { | ||
promise: new Promise(), | ||
fulfill: function (value) { | ||
resolve: function (value) { | ||
this.promise.resolve(value); | ||
@@ -23,0 +23,0 @@ }, |
@@ -77,3 +77,2 @@ /*global describe, it, beforeEach, require, setTimeout */ | ||
triggered = true; | ||
done(); | ||
}); | ||
@@ -83,3 +82,7 @@ | ||
assert.ok(triggered); | ||
/* Wait for a new execution context stack. */ | ||
setTimeout(function () { | ||
assert.ok(triggered); | ||
done(); | ||
}, 50); | ||
}); | ||
@@ -130,7 +133,10 @@ | ||
triggered = true; | ||
done(); | ||
}); | ||
p.reject('error'); | ||
assert.ok(triggered); | ||
/* Wait for a new execution context stack. */ | ||
setTimeout(function () { | ||
assert.ok(triggered); | ||
done(); | ||
}, 50); | ||
}); | ||
@@ -161,2 +167,33 @@ | ||
}); | ||
it('can be used to recover from a rejection', function (done) { | ||
p = new Promise(); | ||
p.reject(new TypeError()); | ||
p2 = p.onRejected(function () { | ||
assert.equal('rejected', p.state()); | ||
return 'Some safe default'; | ||
}); | ||
p2.map(function (x) { | ||
assert.equal('fulfilled', p2.state()); | ||
assert.equal('Some safe default', x); | ||
done(); | ||
}); | ||
}); | ||
it('can chain failures', function (done) { | ||
p = new Promise(); | ||
p.reject(new TypeError()); | ||
p2 = p.onRejected(function () { | ||
assert.equal('rejected', p.state()); | ||
throw new TypeError(); | ||
}); | ||
p2.onRejected(function () { | ||
assert.equal('rejected', p2.state()); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
@@ -204,2 +241,16 @@ | ||
it('encapsulates exceptions in rejections', function (done) { | ||
var exception = new TypeError(); | ||
p4 = p.map(function () { | ||
throw exception; | ||
}); | ||
p4.onRejected(function (r) { | ||
assert.equal('rejected', p4.state()); | ||
assert.equal(exception, r); | ||
done(); | ||
}); | ||
}); | ||
it('fulfils the identity property of a functor', function (done) { | ||
@@ -206,0 +257,0 @@ p.map(function (x) { |
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
81945
1028
479