Models the eventual result of asynchronous computations.
This API is still experimental, so it may change or be removed in future versions. You should not rely on it for production applications.
Models the eventual result of asynchronous computations.
Constructs a Future holding a successful value.
Constructs a future holding a failure value.
Converts a Promise to a folktale Future.
Part of the Applicative instance for Fantasy Land 1.x. See the apply
method for details.
Part of the Applicative instance for Fantasy Land 2.x+. See the apply
method for details.
Part of the Applicative instance for Fantasy Land 2.x+. See the of
method for details.
A container for methods of Futures.
Converts a Future into a Promise.
Returns a textual representation of the Future.
Returns a textual representation of the Future.
Part of the Applicative instance for Fantasy Land 1.x. See the apply
method for details.
Part of the Applicative instance for Fantasy Land 2.x+. See the apply
method for details.
Part of the Bifunctor instance for Fantasy Land 2.x+. See the bimap
method for details.
Part of the Monad instance for Fantasy Land 2.x+. See the chain
method for details.
Part of the Functor instance for Fantasy Land 2.x+. See the map
method for details.
A list of visitors to be invoked when the state of the future changes.
The current state of the Future.
Limited pattern matching for futures.
Adds a visitor to the Future, which will be invoked when the Future's state changes.
Transforms a failed future into a new future.
Transforms a failed future into a new future.
Inverts the state of a Future: successes become failures, failures become successes.
Transforms the succesful value of a future by using a function stored in another future.
Transforms both successful and failure values in a Future, without touching its state.
Transforms a Future's successful value along with its state.
Transforms the successful value of a Future, without touching its state.
Transforms failure values in a Future without touching its state.
Models the eventual result of asynchronous computations.
class Future {
constructor() {
define(this, '_state', Pending());
define(this, '_listeners', []);
}
// ---[ State and configuration ]------------------------------------
/*~
* isRequired: true
* type: |
* get (Future 'f 's) => ExecutionState 'f 's
*/
get _state() {
throw new TypeError('Future.prototype._state should be implemented in an inherited object.');
}
/*~
* isRequired: true
* type: |
* get (Future 'f 's) => Array (DeferredListener 'f 's)
*/
get _listeners() {
throw new TypeError('Future.prototype._listeners should be implemented in an inherited object.');
}
// ---[ Reacting to Future events ]----------------------------------
/*~
* stability: experimental
* type: |
* (Future 'f 's).(DeferredListener 'f 's) => Future 'f 's
*/
listen(pattern) {
this._state.matchWith({
Pending: () => this._listeners.push(pattern),
Cancelled: () => pattern.onCancelled(),
Resolved: ({ value }) => pattern.onResolved(value),
Rejected: ({ reason }) => pattern.onRejected(reason)
});
return this;
}
// --[ Transforming Futures ]----------------------------------------
/*~
* stability: experimental
* type: |
* (Future 'f 's).(('s) => Future 's2) => Future 'f 's2
*/
chain(transformation) {
let deferred = new Deferred(); // eslint-disable-line prefer-const
this.listen({
onCancelled: () => deferred.cancel(),
onRejected: reason => deferred.reject(reason),
onResolved: value => {
transformation(value).listen({
onCancelled: () => deferred.cancel(),
onRejected: reason => deferred.reject(reason),
onResolved: value2 => deferred.resolve(value2)
});
}
});
return deferred.future();
}
/*~
* stability: experimental
* type: |
* (Future 'f 's).(('s) => 's2) => Future 'f 's2
*/
map(transformation) {
return this.chain(value => Future.of(transformation(value)));
}
/*~
* stability: experimental
* type: |
* (Future 'f 's).(Future 'f (('s) => 's2)) => Future 'f 's2
*/
apply(future) {
return this.chain(fn => future.map(fn));
}
/*~
* stability: experimental
* type: |
* (Future 'f 's).(('f) => 'f2, ('s) => 's2) => Future 'f2 's2
*/
bimap(rejectionTransformation, successTransformation) {
let deferred = new Deferred(); // eslint-disable-line prefer-const
this.listen({
onCancelled: () => deferred.cancel(),
onRejected: reason => deferred.reject(rejectionTransformation(reason)),
onResolved: value => deferred.resolve(successTransformation(value))
});
return deferred.future();
}
/*~
* stability: experimental
* type: |
* (Future 'f 's).(('f) => 'f2) => Future 'f2 's
*/
mapRejected(transformation) {
return this.bimap(transformation, x => x);
}
// ---[ Recovering from errors ]-------------------------------------
/*~
* deprecated:
* since: 2.1.0
* replacedBy: .orElse(handler)
*
* type: |
* (Future 'f 's).(('f) => Future 'f2 's2) => Future 'f2 's
*/
recover(handler) {
warnDeprecation('`.recover` was renamed to `.orElse` for consistency, and thus `.recover(handler)` is deprecated. Use `.orElse(handler)` instead.');
return this.orElse(handler);
}
/*~
* stability: experimental
* type: |
* (Future 'f 's).(('f) => Future 'f2 's2) => Future 'f2 's
*/
orElse(handler) {
let deferred = new Deferred(); // eslint-disable-line prefer-const
this.listen({
onCancelled: () => deferred.cancel(),
onResolved: value => deferred.resolve(value),
onRejected: reason => {
handler(reason).listen({
onCancelled: () => deferred.cancel(),
onResolved: value => deferred.resolve(value),
onRejected: newReason => deferred.reject(newReason)
});
}
});
return deferred.future();
}
/*~
* stability: experimental
* type: |
* forall a, b, c, d:
* type Pattern = { r |
* Cancelled: () => Future c d,
* Resolved: (b) => Future c d,
* Rejected: (a) => Future c d
* }
*
* (Future a b).(Pattern) => Future c d
*/
willMatchWith(pattern) {
let deferred = new Deferred(); // eslint-disable-line prefer-const
const resolve = (handler) => (value) => handler(value).listen({
onCancelled: () => deferred.cancel(),
onResolved: (newValue) => deferred.resolve(newValue),
onRejected: (reason) => deferred.reject(reason)
});
this.listen({
onCancelled: resolve(pattern.Cancelled),
onResolved: resolve(pattern.Resolved),
onRejected: resolve(pattern.Rejected)
});
return deferred.future();
}
/*~
* stability: experimental
* type: |
* (Future 'f 's).() => Future 's 'f
*/
swap() {
let deferred = new Deferred(); // eslint-disable-line prefer-const
this.listen({
onCancelled: () => deferred.cancel(),
onRejected: reason => deferred.resolve(reason),
onResolved: value => deferred.reject(value)
});
return deferred.future();
}
// ---[ Debugging ]--------------------------------------------------
/*~
* stability: experimental
* type: |
* (Future 'f 's).() => String
*/
toString() {
const listeners = this._listeners.length;
const state = this._state;
return `folktale:Future(${state}, ${listeners} listeners)`;
}
/*~
* stability: experimental
* type: |
* (Future 'f 's).() => String
*/
inspect() {
return this.toString();
}
/*~
* stability: experimental
* type: |
* forall e, v:
* (Future e v).() => Promise v e
*/
toPromise() {
return require('folktale/conversions/future-to-promise')(this);
}
}