An asynchronous promise loosely represents the eventual result of a function. A promise is initially "unresolved" and may eventually become "resolved". A resolution can either be "fulfilled" with a value or "rejected" with a reason, corresponding by analogy to synchronously returned values and thrown exceptions respectively. Once a promise has become resolved, it cannot be resolved again, so a promise's fulfillment value or rejection reason are guaranteed to be the same across multiple observations. Although the identity of the value or reason cannot change, their properties may be mutable.
Thenable Promises
Thenable promises are sufficent for modeling fulfillment and rejection of promises within a single program. If promises are needed to model remote objects between cooperating event loops (like workers, processes, and network clients, servers, and peers), they can either be extended with the message passing "sendable promises" system, or assimilated by a sendable promise manager system. If a thenable promise is provided by a system that is suspicious for safety or security reasons, it is necessary to use a promise manager to provide the normative guarantees of this specification and the stricter guarantees provided by the promise manager specification.
-
A promise is an object (that may be a function) with a
then
function.-
When using promises, the existence of a
then
function must be sufficient to distinguish a promise from any other value. -
then
accepts afulfilled
callback and arejected
callback. -
then
may be called any number of times to register multiple observers. -
The callbacks registered by any
then
call must not be called after callbacks registered in a laterthen
call. -
Callbacks should not be called before
then
returns. -
fulfilled
andrejected
are both optional arguments. -
If truthy,
fulfilled
must accept a value as its only argument.-
The
fulfilled
callback must be called after the promise is fulfilled. -
The
fulfilled
callback must not be called more than once. -
The
fulfilled
callback must not be called if therejected
callback has been called.
-
-
If truthy,
rejected
must accept a rejection reason as its only argument.-
The
rejected
callback must be called after the promise has been rejected. -
The
rejected
callback must not be called more than once. -
The
rejected
callback must not be called if thefulfilled
callback has been called.
-
-
then
must return a thenable promise.-
The returned promise must be fulfilled with the value returned by either callback.
-
The returned promise must be rejected if either callback throws an exception.
- The reason for the rejection must be the error thrown by the callback.
-
-
Thenable Promise Manager
-
A promise manager is an object with the following functions for creating and manipulating promises.
-
defer(annotation)
-
Annotation is an optional string describing the operation being deferred, which may be used by debuggers to assist in the visualization of when promises are made and resolved.
-
Returns an object with
promise
,resolve
, andreject
properties. -
promise
is a promise (the "deferred promise"). -
resolve
is a function that accepts a promise or a value.-
Ignores all resolutions after the first resolution.
-
If the value is a promise, resolves the deferred promise with the resolved promise, such that any observations of the resolved promise are forwarded to the deferred promise.
-
If the value is not a promise, fulfills the deferred promise with the resolved value.
-
-
reject
is a function that accepts a rejection reason-
The rejection reason may be any value.
-
Resolves the deferred promise with a rejection promise for the given reason.
-
-
All functions of the deferred object may be called without being bound to the deferred object.
-
-
when(value, fulfilled, rejected)
-
value
may be a promise or any other value.- Non-promise values are equivalent to fulfilled promises with that value.
-
Arranges for
fulfilled
to be called-
if
fulfilled
is truthy -
with the fulfilled value as its argument
-
not before
when
returns -
if and when the value is fulfilled
-
at most once
-
if
rejected
has not been called
-
-
Arranges for
rejected
to be called-
if
rejected
is truthy -
with the reason for rejection as its argument
-
not before
when
returns -
if and when the promised value is rejected
-
at most once
-
if
fulfilled
has not been called
-
-
Must return a promise
-
that must be resolved if and when
fulfilled
orrejected
return a value or promise, with that value or promise as the resolution. -
that must be rejected if and when
fulfilled
orrejected
throw an error, with the error as the reason for rejection.
-
-
-
resolve(value)
-
value
may be a promise or any other value.-
If
value
is a promise, returns that promise. -
If
value
is not a promise, returns a promise that has already been fulfilled with the value.
-
-
-
reject(reason)
-
Returns a promise that has been rejected for the given reason.
-
The reason may be any value.
-
-
isPromise(value)
- Returns a boolean value of whether the given value is a promise.
-
isResolved(value)
-
Returns a boolean value of whether the given value is a resolved promise.
-
value
may be any value.
-
-
isFulfilled(value)
-
Returns a boolean value of whether the given value is a resolved and fulfilled promise.
-
value
may be any value.
-
-
isRejected(value)
-
Returns a boolean value of whether the given value is a resolved and rejected promise.
-
value
may be any value.
-
-
Sendable Promises
If a promise is a remote object or a proxy for a remote object, in addition to being able to observe fulfillment and rejection, it is useful to be able to pipeline "messages" to such promises so that the remote promise can rapidly dispatch responses to those messages. It is also useful to have promises for remote objects and proxies for remote objects that are not serializable, such as stateful functions or functions that provide access to capabilities.
-
A promise is an object (that may be a function) with a
promiseSend
function.-
When using promises, the existence of a
promiseSend
function must be sufficient to distinguish a promise from any other value. -
The
promiseSend
function must accept an "operator name" as its first argument. -
Operator names are an extensible set of strings. The following operators are reserved:
-
"when"
, in which case the third argument must be a rejection callback.- A rejection callback must accept a rejection reason (any value) as its argument.
-
"get"
in which case the third argument is a property name (string). -
"put"
in which case the third argument is a property name (string) and the fourth is a value for the new property. -
"del"
in which case the third argument is a property name. -
"post"
in which case the third argument is a property name and all subsequent arguments are variadic.
-
-
The
promiseSend
function must accept a resolver function as its second argument.- The resolver function may eventually be called with a value or a promise as its argument.
-
The
promiseSend
function may receive variadic arguments. -
The
promiseSend
function must returnundefined
.
-
-
A sendable promise may also be a thenable promise.
Any thenable promise can be trivially wrapped with a sendable promise that implements all of the object-oriented operators by waiting for the promise to be fulfilled and then performing the corresponding operation. So, it is only necessary for a promise to implement promiseSend if it is on the boundary between two processes.
Sendable Promise Manager
A sendable promise manager extends the thenable promise manager system with functions that can forward messages to a promise, returning promises for the fulfilled object's response. It also provides tools for sending and handling messages, and for annotating an object that is not serializable.
-
A sendable promise manager creates and manipulates both sendable promises and thenable promises.
-
A sendable promise manager must support the thenable promise manager specification.
-
A sendable promise manager must support the following additional functions.
-
get
,put
,del
,post
,invoke
are functions.-
These functions must accept an object as their first argument.
-
The object may be a promise or any other value.
-
If object is not a promise, it is treated as a fulfilled promise with its value.
-
-
These functions must return a promise.
-
The promise must be rejected with the same reason if the object promise is rejected.
-
The promise must be rejected if the object promise is fulfilled with a type that does not support properties.
-
-
-
get(object, name)
- Must fulfill the returned promise with the named property of of the object if and when it is fulfilled.
-
put(object, name, value)
-
Must fulfill the returned promise with
undefined
if and when the object is fulfilled and the named property has been assigned the value. -
Must reject the returned promise if the object is fulfilled and setting the named property to value throws an exception.
-
-
del(object, name)
-
Must fulfill the returned promise with
undefined
if and when the object is fulfilled and an attempt has been made to delete the named property . -
Must reject the returned promise with an exception if the object is fulfilled and attempting to delete the named property throws an exception.
-
-
post(object, name, args)
-
Must apply the
args
to the named function of object if and when it is fullfilled.-
Must resolve the returned promise with the return value of that application.
-
Must reject the returned promise if that application throws an error, using the error as the reason for rejection.
-
-
-
invoke(object, name, ...args)
-
Must apply the spread, variadic
args
to the named function of object if and when it is fullfilled.-
Must resolve the returned promise with the return value of that application.
-
Must reject the returned promise if that application throws an error, using the error as the reason for rejection.
-
-
-
keys(object)
- Must fulfill the returned promise with an array of the owned property names of the object if and when it is fulfilled.
-
makePromise(handlers, fallback)
-
Returns a sendable promise
-
Accepts a
handlers
object that maps message names to handler functions that return values or promises, particularly:-
when(rejected)
-
get(name)
-
put(name)
-
del(name)
-
post(name, args)
-
-
Accepts a
fallback(operator, resolve, ...args)
function -
promiseSend(operator, resolve, ...args)
calls the handler with the given operator name from handlers if one is truthy.-
Calls the handler with the spreaded, variadic arguments only.
-
Calls resolve with the value returned by the handler.
-
-
promiseSend(operator, resolve, ...args)
call the fallback function if property of the handlers mapping for the given operator name is falsy.-
Calls fallback with the operator and the spreaded, variadic arguments only.
-
Calls resolve with the value returned by the fallback function.
-
-
-
send(operator, ...args)
-
Constructs a deferred.
-
Calls
promiseSend(operator, resolve, ...args)
-
Where
resolve
is the resolve function of the deferred. -
Not before
send
returns.
-
-
Returns the deferred promise.
-
-
resolve(value)
-
Must support
ref
as defined by the thenable promise manager specification. -
Must handle the following messages (per
makePromise
):-
when(errback)
, ignores the errback and returnsvalue
. -
get(name)
, returns the named property ofvalue
. -
put(name, value)
, sets the named property to the given value of the ref value and returnsundefined
. -
del(name)
, deletes the named property of the resolved value and returnsundefined
. -
post(name, args)
, calls the named function of the value and returns the returned value.
-
-
Must reject all other messages with the reason
"Promise does not handle OPERATOR"
whereOPERATOR
is the message operator.
-
-
reject(reason)
-
Must support
reject
as defined by the thenable promise manager specification. -
Handles the
"when"
operator:-
If the
rejected
callback is truthy, calls therejected
callback withreason
and returns the value that the callback returns. -
Otherwise, returns a rejected promise with
reason
.
-
-
Handles all other messages by forwarding its own reason for rejection.
-
-
defer(annotation)
-
Must support
defer
as defined by the thenable promise manager specification. -
Must eventually forward all messages received to the
ref
promise representing the resolution of itspromise
.
-
-