Pacta
An algebraic implementation of ECMAScript 2015 and Promises/A+ Promises in JavaScript for as many browsers and Node.js versions as possible
Install / Use
/learn @mudge/PactaREADME
Pacta 
An algebraic implementation of ECMAScript 2015 and Promises/A+ Promises in JavaScript for as many browsers and Node.js versions as possible.
Current version: 0.9.0
Supported Node.js versions: 0.6, 0.8, 0.10, 0.11, 0.12, 4.0, 4.1, 5.0
Supported browsers: Internet Explorer 6+, Firefox 3.6+, Chrome 14+, Opera 10.6+, Safari 4+, iOS 3+, Windows Phone 8.1, Android 2.2+
var promise = new Promise(function (resolve, reject) {
setTimeout(function () { resolve('Hello'); }, 5000);
setTimeout(function () { reject('Timeout!'); }, 60000);
});
promise
.then(function (value) { return value + ', World!'; })
.catch(function (reason) { return 'Sorry'; })
.then(console.log); //=> Hello, World!
Installation
$ npm install pacta # for Node.js
$ bower install pacta # for the browser
Alternatively, include pacta.js via a <script/> in your page (Pacta also
supports using an AMD
API-compliant loader such as RequireJS).
Promises
Promises can be thought of as objects representing a value that may not have
been calculated yet (they are sometimes referred to as Deferreds).
An obvious example is the result of an asynchronous HTTP request: it's not clear when the request will be fulfilled but it will be at some point in the future. Having actual Promise objects representing these eventual values allows you to compose, transform and act on them without worrying about their time or sequence of execution.
At their most basic, an empty promise can be created and resolved like so:
var Promise = require('pacta');
var p = new Promise(function (resolve) {
setTimeout(function () {
/* Populate the promise with its final value. */
resolve(1);
}, 1000);
});
Promises can also be marked as rejected (viz. represent an error state) like
so:
var p = new Promise(function (resolve, reject) {
/* Mark the promise as rejected with a reason. */
reject('The server could not be found.');
});
Concretely, a promise can be represented by the following deterministic finite automaton:
<p align="center"><img src="images/dfa.png" width="275" height="192" alt=""></p>For a worked example of using promises, see the sample HTTP client and two example programs included in Pacta.
ECMAScript 2015
Pacta's promises comply with the Promise API described in ECMAScript 2015 and the Promises/A+ specification:
new Promise(executor)for constructing, resolving and rejecting promises;Promise#then(onFulfilled, onRejected)for binding callbacks on promise resolution or rejection (compliant with the Promises/A+ specification);Promise#catch(onRejected)for dealing with rejected promises;Promise.all(iterable)for returning a promise that is resolved when all of the promises in an iterable resolve, or rejects with the reason of the first rejected promise;Promise.race(iterable)for returning a promise that resolves or rejects as soon as one of the promises in an iterable resolves or rejects;Promise.reject(reason)for constructing rejected promises;Promise.resolve(value)for constructing resolved promises.
Algebraic JavaScript
The aforementioned high level functions are implemented in terms of the algebraic primitives defined in the "Fantasy Land" Algebraic JavaScript Specification:
- Semigroups (through
Promise#concatwhich concatenates promises containing semigroups such as arrays and strings); - Monoids (through
Promise#emptywhich returns an empty version of a promise that contains a monoid); - Functors (through
Promise#map); - Applicative
(through
Promise#apandPromise.of); - Chains (through
Promise#chain); - Monads (through all of the above).
These different specifications can be thought of as different levels of abstraction with ECMAScript 2015 at the top and Fantasy Land at the bottom, e.g.
| Specification | Functions |
| --------------- | ----------------------------------------------------------------------------------- |
| ECMAScript 2015 | Promise.all, Promise.race, Promise.resolve, Promise.reject, Promise#catch |
| Promises/A+ | Promise#then |
| Fantasy Land | Promise#map, Promise#concat, Promise#chain, etc. |
Pacta gives you access to all of these functions including the algebraic primitives for composition into more expressive operations.
Working with lists of promises
As well as the standard Promise.all and
Promise.race, Pacta also provides the following
functions for creating and working with Promises of lists:
Promise#conjointo concatenate promises into a list of values regardless of their original type meaning that non-Monoid types can be combined with others (e.g. a promise of'foo'can be conjoined with[1, 2]to produce['foo', 1, 2]);Promise#appendto append promises to an initial promise of a list. This means that you can work more easily with multiple promises of lists without joining them together (as would be done withconcatandconjoin), e.g. appending a promise of[2, 3]to a promise of[1]results in[1, [2, 3]]rather than[1, 2, 3]);Promise#reduceto reduce a list within a promise;Promise#spreadto map over a promise's value but, instead of receiving a single value, spread the promise's value across separate arguments:
Promise.all([1, 2]).spread(function (x, y) {
console.log(x); //=> 1
console.log(y); //=> 2
});
It also defines a monoid interface for Array and String, implementing
empty such that:
Array.empty(); //=> []
String.empty(); //=> ""
See the test suite for more information.
API Documentation
new Promise([executor])
var promise = new Promise();
var promise = new Promise(function (resolve, reject) {
if (foo) {
resolve('Huzzah!');
} else {
reject('Oops!');
}
});
Create a new, unfulfilled promise that will eventually be populated with a
value either by an optionally passed executor function (which is passed a
resolve and a reject function) or by Promise#resolve
and Promise#reject.
See also
Promise#then([onFulfilled[, onRejected]])
promise.then(function (value) {
return x * 2;
}); //=> Promise.resolve(4)
promise.then(function (value) {
return Promise.resolve(x * 2);
}); //=> Promise.resolve(4)
promise.then(function (value) {
console.log('Success!', value);
}, function (reason) {
console.error('Error!', reason);
});
An implementation of the Promises/A+ then
method, taking an
optional onFulfilled and onRejected function to call when the promise is
fulfilled or rejected respectively.
Like Promise#map, then returns a promise itself and can be
chained.
Unlike Promise#map, then will unwrap any promise that is
returned by an onFulfilled or onRejected function (making then behave
like Promise#chain).
See also
- Promise.prototype.then() - JavaScript | MDN
- The
thenMethod - Promises/A+ - Promise.prototype.then ( onFulfilled , onRejected ) - ECMAScript 2015 Language Specification
Promise#catch(onRejected)
promise.catch(function (reason) {
console.error('Error!', reason);
});
An implementation of ECMAScript 2015's catch method, equivalent to calling
Promise#then with an undefined
onFulfilled.
Unlike [Promise#onRejected]
