Promises/D

From CommonJS Spec Wiki
Jump to: navigation, search

STATUS: PROPOSAL

Implementations
[[Implementations/node.js|]] (https://github.com/kriskowal/q)

Specification

The following defines a promise:

  1. A promise is an object (or a function) that implements the "promiseSend" method.
    1. In the context of a promise library, the existence of a "promiseSend" method must be sufficient to distinguish a promise from any other value.
    2. The "promiseSend" method must accept an operator name as its first argument.
    3. Operator names are an extensible set. The following operators are reserved:
      1. "when" in which case the third argument must be a rejection callback.
        1. A rejection callback must accept a rejection reason (any value) as its argument.
      2. "get" in which case the third argument is a property name (string).
      3. "put" in which case the third argument is a property name (string) and the fourth is a value for the new property.
      4. "del" in which case the third argument is a property name.
      5. "post" in which case the third argument is a property name and all subsequent arguments are variadic.
      6. "isDef"
    4. The "promiseSend" method must accept a resolver function as its second argument.
    5. The "promiseSend" method may receive variadic arguments.
    6. The "promiseSend" method must return "undefined".

The following additional constraints are placed on implementations of Promises/B:

  1. ref: The "ref(value)" method returns a promise. If the given value is already promise, it is returned. Otherwise, the returned promise must:
    1. Accept "when" messages by eventually calling the resolver function with the value
    2. Accept "get" messages by eventually calling the resolver function with the property named by the third argument of the wrapped object.
    3. Accept "put" messages by eventually calling the resolver function after setting the property named by the third argument of the wrapped object to the value given in the fourth argument.
    4. Accept "del" messages by eventually calling the resolver function after deleting the property named by the third argument of the wrapped object.
    5. Accept "post" messages by eventually calling resolver function with the return value of the method named by the third argument of the wrapped object and all variadic arguments.
    6. Reject all other messages by calling the resolver with a rejection promise (as returned by reject).
    7. Respond to "valueOf" by returning the wrapped value.
  2. reject: The "reject(reason)" method returns a promise. That promise must:
    1. Accept "when" messages.
      1. If a rejection callback is provided, the rejection callback must be eventually called with the given reason.
      2. Then, the resolution callback must be eventually called with the return value of the rejection callback.
      3. Otherwise, the resolution callback must be eventually called with a rejection promise with the given reason.
    2. For all other messages, the resolution callback must be eventually called with a rejection promise with the given reason.
    3. Respond to "valueOf" by returning an object with a "reason" property containing the given reason, and a truthy "promiseRejection" property.
  3. def: The "def(value)" method returns a promise. It should first wrap the value with "ref(value") to create the wrapped promise. The returned promise must:
    1. Accept "isDef" messages by eventually calling the resolver function with no arguments
    2. Eventually forward all other messages to the wrapped promise
    3. Respond to "valueOf" by returning from the "valueOf" method of the wrapped promise.
  4. defer: The "defer()" method returns an object with "promise", "resolve", and "reject" methods. The "resolve(value)" method accepts a value and wraps it in a promise (if it is not a promise already) by calling "ref(value)". The "reject(reason)" method is a convenience that calls "resolve" with a rejection promise. The deferred promise must:
    1. Eventually forward all received messages to the resolution promise in the order in which they were received
    2. Respond to "valueOf" by returning from the "valueOf" method of the wrapped value (if resolved) or itself (if not resolved).
  5. All "eventual" calls must occur in separate and sequential turns of the JavaScript event loop.

Non-normative clauses are denoted in italics. These are provided to give context to the normative clauses, and are generally correspond to normative clauses of Promises/B.

Philosophy

This specification is intended to enable run-time interoperable implementations of Promises/B. This specification is not, nor is Promises/A, in conflict with the opacity clause of Promises/B, although Promises/A is not sufficient to implement "get", "put", and "post" of Promises/B. The opacity clause is intended to permit further development of this nature on the implementations of Promises/B orthogonally from development of modules that use Promises/B implementations.

The duck-type method name "promiseSend" is deliberately chosen to be unlikely to collide with other values, but still readable when encountered in debugging. It is necessary to use a duck-method for multiple instances of the promise module to interoperate in the same run-time, which is possible when using package managers like Isaac Schlueter's NPM for Node and different packages depend on different specific versions of the promise module. The name was not chosen to be brief and ergonomic since its direct use by libraries other than imlementations of Promises/B is discouraged by the opacity clause of that specification.

Discussion