Giter VIP home page Giter VIP logo

promises-unwrapping's Introduction

Status

This proposal has progressed to the Draft ECMAScript 6 Specification, which is available for review on the official ECMAScript wiki. When referencing the promises specification, you should reference the draft ECMAScript 6 spec, and not this repository.

We are still using this repository as a way to fix the remaining issues with the promises specification, and as such it may be slightly ahead of the draft specification as we perform that work. However, we must emphasize it is only a staging ground.

Promise Objects

A Promise is an object that is used as a placeholder for the eventual results of a deferred (and possibly asynchronous) computation.

Any Promise object is in one of three mutually exclusive states: fulfilled, rejected, and pending:

  • A promise p is fulfilled if p.then(f, r) will immediately enqueue a Task to call the function f.
  • A promise p is rejected if p.then(f, r) will immediately enqueue a Task to call the function r.
  • A promise is pending if it is neither fulfilled nor rejected.

A promise said to be settled if it is not pending, i.e. if it is either fulfilled or rejected.

A promise is resolved if it is settled or if it has been "locked in" match the state of another promise. Attempting to resolve or reject a resolved promise has no effect. A promise is unresolved if it is not resolved. An unresolved promise is always in the pending state. A resolved promise may be pending, fullfilled, or rejected.

Promise Abstract Operations

PromiseCapability Records

A PromiseCapability is a Record value used to encapsulate a promise object along with the functions that are capable of resolving or rejecting that promise object. PromiseCapability records are produced by the NewPromiseCapability abstract operation.

PromiseCapability Records have the fields listed in this table.

PromiseCapability Record Fields
Field Name Value Meaning
[[Promise]] An object An object that is usable as a promise.
[[Resolve]] A function object The function that is used to resolve the given promise object.
[[Reject]] A function object The function that is used to reject the given promise object.

IfAbruptRejectPromise ( value, capability )

IfAbruptRejectPromise is a short hand for a sequence of algorithm steps that use a PromiseCapability record. An algorithm step of the form:

  1. IfAbruptRejectPromise(value, capability).

means the same things as:

  1. If value is an abrupt completion,
    1. Let rejectResult be the result of calling the [[Call]] internal method of capability.[[Reject]] with undefined as thisArgument and (value.[[value]]) as argumentsList.
    2. ReturnIfAbrupt(rejectResult).
    3. Return capability.[[Promise]].
  2. Else if value is a Completion Record, then let value be value.[[value]].

PromiseReaction Records

The PromiseReaction is a Record value used to store information about how a promise should react when it becomes resolved or rejected with a given value. PromiseReaction records are created by the then method of the Promise prototype, and are used by a PromiseReactionTask.

PromiseReaction records have the fields listed in this table.

PromiseReaction Record Fields
Field Name Value Meaning
[[Capabilities]] A PromiseCapability record The capabilities of the promise for which this record provides a reaction handler.
[[Handler]] A function object, or a String The function that should be applied to the incoming value, and whose return value will govern what happens to the derived promise. If [[Handled]] is "Identity" it is equivalent to a function that simply returns its first argument. If [[Handler]] is "Thrower" it is equivalent to a function that throws its first argument as an exception.

CreateResolvingFunctions ( promise )

When CreateResolvingFunctions is performed with argument promise, the following steps are taken:

  1. Let alreadyResolved be a new Record { [[value]]: false }.
  2. Let resolve be a new built-in function object as defined in Promise Resolve Functions.
  3. Set the [[Promise]] internal slot of resolve to promise.
  4. Set the [[AlreadyResolved]] internal slot of resolve to alreadyResolved.
  5. Let reject be a new built-in function object as defined in Promise Reject Functions.
  6. Set the [[Promise]] internal slot of reject to promise.
  7. Set the [[AlreadyResolved]] internal slot of reject to alreadyResolved.
  8. Return a new Record { [[Resolve]]: resolve, [[Reject]]: reject }.

Promise Reject Functions

A promise reject function is an anonymous built-in function that has [[Promise]] and [[AlreadyResolved]] internal slots.

When a promise reject function F is called with argument reason, the following steps are taken:

  1. Assert: F has a [[Promise]] internal slot whose value is an Object.
  2. Let promise be the value of F's [[Promise]] internal slot.
  3. Let alreadyResolved be the value of F's [[AlreadyResolved]] internal slot.
  4. If alreadyResolved.[[value]] is true, then return undefined.
  5. Set alreadyResolved.[[value]] to true.
  6. Return RejectPromise(promise, reason).

Promise Resolve Functions

A promise resolve function is an anonymous built-in function that has [[Promise]] and [[AlreadyResolved]] internal slots.

When a promise resolve function F is called with argument resolution, the following steps are taken:

  1. Assert: F has a [[Promise]] internal slot whose value is an Object.
  2. Let promise be the value of F's [[Promise]] internal slot.
  3. Let alreadyResolved be the value of F's [[AlreadyResolved]] internal slot.
  4. If alreadyResolved.[[value]] is true, then return undefined.
  5. Set alreadyResolved.[[value]] to true.
  6. If SameValue(resolution, promise) is true, then
    1. Let selfResolutionError be a newly-created TypeError object.
    2. Return RejectPromise(promise, selfResolutionError).
  7. If Type(resolution) is not Object, then
    1. Return FulfillPromise(promise, resolution).
  8. Let then be Get(resolution, "then").
  9. If then is an abrupt completion, then
    1. Return RejectPromise(promise, then.[[value]]).
  10. Let then be then.[[value]].
  11. If IsCallable(then) is false, then
    1. Return FulfillPromise(promise, resolution).
  12. Perform EnqueueTask("PromiseTasks", ResolvePromiseViaThenableTask, (promise, resolution, then)).
  13. Return undefined.

FulfillPromise ( promise, value )

  1. Assert: the value of promise's [[PromiseState]] internal slot is "pending".
  2. Let reactions be the value of promise's [[PromiseFulfillReactions]] internal slot.
  3. Set the value of promise's [[PromiseResult]] internal slot to value.
  4. Set the value of promise's [[PromiseFulfillReactions]] internal slot to undefined.
  5. Set the value of promise's [[PromiseRejectReactions]] internal slot to undefined.
  6. Set the value of promise's [[PromiseState]] internal slot to "fulfilled".
  7. Return TriggerPromiseReactions(reactions, value).

NewPromiseCapability ( C )

The abstract operation NewPromiseCapability takes a constructor function, and attempts to use that constructor function in the fashion of the built-in Promise constructor to create a Promise object and extract its resolve and reject functions. The promise plus the resolve and reject functions are used to initialise a new PromiseCapability record which is returned as the value of this abstract operation.

  1. If IsConstructor(C) is false, throw a TypeError.
  2. Assert: C is a constructor function that supports the parameter conventions of the Promise constructor.
  3. Let promise be CreateFromConstructor(C).
  4. ReturnIfAbrupt(promise).
  5. If Type(promise) is not Object, then throw a TypeError exception.
  6. Return CreatePromiseCapabilityRecord(promise, C).

NOTE: This abstract operation supports Promise subclassing, as it is generic on any constructor that calls a passed executor function argument in the same way as the Promise constructor. It is used to generalize static methods of the Promise constructor to any subclass.

CreatePromiseCapabilityRecord ( promise, constructor )

  1. Assert: promise is an uninitialized object created as if by invoking @@create on constructor.
  2. Let promiseCapability be a new PromiseCapability { [[Promise]]: promise, [[Resolve]]: undefined, [[Reject]]: undefined }.
  3. Let executor be a new built-in function object as defined in GetCapabilitiesExecutor Functions.
  4. Set the [[Capability]] internal slot of executor to promiseCapability.
  5. Let constructorResult be the result of calling the [[Call]] internal method of constructor, passing promise and (executor) as the arguments.
  6. ReturnIfAbrupt(constructorResult).
  7. If IsCallable(promiseCapability.[[Resolve]]) is false, then throw a TypeError exception.
  8. If IsCallable(promiseCapability.[[Reject]]) is false, then throw a TypeError exception.
  9. If Type(constructorResult) is Object and SameValue(promise, constructorResult) is false, then throw a TypeError exception.
  10. Return promiseCapability.

GetCapabilitiesExecutor Functions

A GetCapabilitiesExecutor function is an anonymous built-in function that has a [[Capability]] internal slot.

When a GetCapabilitiesExecutor function F is called with arguments resolve and reject the following steps are taken:

  1. Assert: F has a [[Capability]] internal slot whose value is a PromiseCapability Record.
  2. Let promiseCapability be the value of F's [[Capability]] internal slot.
  3. If promiseCapability.[[Resolve]] is not undefined, then throw a TypeError exception.
  4. If promiseCapability.[[Reject]] is not undefined, then throw a TypeError exception.
  5. Set promiseCapability.[[Resolve]] to resolve.
  6. Set promiseCapability.[[Reject]] to reject.
  7. Return undefined.

RejectPromise ( promise, reason )

  1. Assert: the value of promise's [[PromiseState]] internal slot is "pending".
  2. Let reactions be the value of promise's [[PromiseRejectReactions]] internal slot.
  3. Set the value of promise's [[PromiseResult]] internal slot to reason.
  4. Set the value of promise's [[PromiseFulfillReactions]] internal slot to undefined.
  5. Set the value of promise's [[PromiseRejectReactions]] internal slot to undefined.
  6. Set the value of promise's [[PromiseState]] internal slot to "rejected".
  7. Return TriggerPromiseReactions(reactions, reason).

IsPromise ( x )

The abstract operation IsPromise checks for the promise brand on an object.

  1. If Type(x) is not Object, return false.
  2. If x does not have a [[PromiseState]] internal slot, return false.
  3. If the value of x's [[PromiseState]] internal slot is undefined, return false.
  4. Return true.

TriggerPromiseReactions ( reactions, argument )

The abstract operation TriggerPromiseReactions takes a collection of functions to trigger in the next Task, and calls them, passing each the given argument. Typically, these reactions will modify a previously-returned promise, possibly calling in to a user-supplied handler before doing so.

  1. Repeat for each reaction in reactions, in original insertion order
    1. Perform EnqueueTask("PromiseTasks", PromiseReactionTask, (reaction, argument)).
  2. Return undefined.

Promise Tasks

PromiseReactionTask ( reaction, argument )

The task PromiseReactionTask with parameters reaction and argument applies the appropriate handler to the incoming value, and uses the handler's return value to resolve or reject the derived promise associated with that handler.

  1. Assert: reaction is a PromiseReaction Record.
  2. Let promiseCapability be reaction.[[Capabilities]].
  3. Let handler be reaction.[[Handler]].
  4. If handler is "Identity", then let handlerResult be NormalCompletion(argument).
  5. Else if handler is "Thrower", then let handlerResult be Completion{ [[type]]: throw, [[value]]: argument, [[target]]: empty }.
  6. Else, let handlerResult be the result of calling the [[Call]] internal method of handler passing undefined as thisArgument and (argument) as argumentsList.
  7. If handlerResult is an abrupt completion, then
    1. Let status be the result of calling the [[Call]] internal method of promiseCapability.[[Reject]] passing undefined as thisArgument and (handlerResult.[[value]]) as argumentsList.
    2. NextTask status.
  8. Let handlerResult be handlerResult.[[value]].
  9. Let status be the result of calling the [[Call]] internal method of promiseCapability.[[Resolve]] passing undefined as thisArgument and (handlerResult) as argumentsList.
  10. NextTask status.

ResolvePromiseViaThenableTask ( promiseToResolve, thenable, then )

The task ResolvePromiseViaThenableTask with parameters promiseToResolve, thenable, and then uses the supplied thenable and its then method to resolve the given promise. This process must take place in an enqueued task to ensure that code inside the then method cannot disrupt the invariants of surrounding code.

  1. Let resolvingFunctions be CreateResolvingFunctions(promiseToResolve).
  2. Let thenCallResult be the result of calling the [[Call]] internal method of then passing thenable as thisArgument and (resolvingFunctions.[[Resolve]], resolvingFunctions.[[Reject]]) as argumentsList.
  3. If thenCallResult is an abrupt completion,
    1. Let status be the result of calling the [[Call]] internal method of resolvingFunctions.[[Reject]] passing undefined as thisArgument and (thenCallResult.[[value]]) as argumentsList.
    2. NextTask status.
  4. NextTask thenCallResult.

The Promise Constructor

The Promise constructor is the %Promise% intrinsic object and the initial value of the Promise property of the global object. When Promise is called as a function rather than as a constructor, it initialises its this value with the internal state necessary to support the Promise.prototype methods.

The Promise constructor is designed to be subclassable. It may be used as the value in an extends clause of a class definition. Subclass constructors that intend to inherit the specified Promise behaviour must include a super call to Promise.

Promise ( executor )

When the Promise function is called with argument executor the following steps are taken:

  1. Let promise be the this value.
  2. If Type(promise) is not Object, then throw a TypeError exception.
  3. If promise does not have a [[PromiseState]] internal slot, then throw a TypeError exception.
  4. If promise's [[PromiseState]] internal slot is not undefined, then throw a TypeError exception.
  5. If IsCallable(executor) is false, then throw a TypeError exception.
  6. Return InitialisePromise(promise, executor).

NOTE

The executor argument must be a function object. It is called for initiating and reporting completion of the possibly deferred action represented by this Promise object. The executor is called with two arguments: resolve and reject. These are functions that may be used by the executor function to report eventual completion or failure of the deferred computation. Returning from the executor function does not mean that the deferred action has been completed but only that the request to eventually perform the deferred action has been accepted.

The resolve function that is passed to an executor function accepts a single argument. The executor code may eventually call the resolve function to indicate that it wishes to resolve the associated Promise object. The argument passed to the resolve function represents the eventual value of the deferred action and can be either the actual fulfillment value or another Promise object which will provide the value if it is fullfilled.

The reject function that is passed to an executor function accepts a single argument. The executor code may eventually call the reject function to indicate that the associated Promise is rejected and will never be fulfilled. The argument passed to the reject function is used as the rejection value of the promise. Typically it will be an Error object.

The resolve and reject functions passed to an executor function by the Promise constructor have the capability to actually resolve and reject the associated promise. Subclasses may have different constructor behaviour that passes in customized values for resolve and reject.

InitialisePromise ( promise, executor )

The abstract operation InitialisePromise initialises a newly allocated promise object using an executor function.

  1. Assert: promise has a [[PromiseState]] internal slot and its value is undefined.
  2. Assert: IsCallable(executor) is true.
  3. Set promise's [[PromiseState]] internal slot to "pending".
  4. Set promise's [[PromiseFulfillReactions]] internal slot to a new empty List.
  5. Set promise's [[PromiseRejectReactions]] internal slot to a new empty List.
  6. Let resolvingFunctions be CreateResolvingFunctions(promise).
  7. Let completion be the result of calling the [[Call]] internal method of executor with undefined as thisArgument and (resolvingFunctions.[[Resolve]], resolvingFunctions.[[Reject]]) as argumentsList.
  8. If completion is an abrupt completion, then
    1. Let status be the result of calling the [[Call]] internal method of resolvingFunctions.[[Reject]] with undefined as thisArgument and (completion.[[value]]) as argumentsList.
    2. ReturnIfAbrupt(status).
  9. Return promise.

new Promise ( ... argumentsList )

When Promise is called as part of a new expression it is a constructor: it initialises a newly created object.

Promise called as part of a new expression with argument list argumentsList performs the following steps:

  1. Let F be the Promise function object on which the new operator was applied.
  2. Let argumentsList be the argumentsList argument of the [[Construct]] internal method that was invoked by the new operator.
  3. Return Construct(F, argumentsList).

If Promise is implemented as an ECMAScript function object, its [[Construct]] internal method will perform the above steps.

Properties of the Promise Constructor

The value of the [[Prototype]] internal slot of the Promise constructor is the Function prototype object.

Besides the length property (whose value is 1), the Promise constructor has the following properties:

Promise.all ( iterable )

The all function returns a new promise which is fulfilled with an array of fulfillment values for the passed promises, or rejects with the reason of the first passed promise that rejects. It resolves all elements of the passed iterable to promises as it runs this algorithm.

  1. Let C be the this value.
  2. Let promiseCapability be NewPromiseCapability(C).
  3. ReturnIfAbrupt(promiseCapability).
  4. Let iterator be GetIterator(iterable).
  5. IfAbruptRejectPromise(iterator, promiseCapability).
  6. Let values be ArrayCreate(0).
  7. Let remainingElementsCount be a new Record { [[value]]: 1 }.
  8. Let index be 0.
  9. Repeat
    1. Let next be IteratorStep(iterator).
    2. IfAbruptRejectPromise(next, promiseCapability).
    3. If next is false,
      1. Set remainingElementsCount.[[value]] to remainingElementsCount.[[value]] - 1.
      2. If remainingElementsCount.[[value]] is 0,
        1. Let resolveResult be the result of calling the [[Call]] internal method of promiseCapability.[[Resolve]] with undefined as thisArgument and (values) as argumentsList.
        2. ReturnIfAbrupt(resolveResult).
      3. Return promiseCapability.[[Promise]].
    4. Let nextValue be IteratorValue(next).
    5. IfAbruptRejectPromise(nextValue, promiseCapability).
    6. Let nextPromise be Invoke(C, "resolve", (nextValue)).
    7. IfAbruptRejectPromise(nextPromise, promiseCapability).
    8. Let resolveElement be a new built-in function object as defined in Promise.all Resolve Element Functions.
    9. Set the [[AlreadyCalled]] internal slot of resolveElement to false.
    10. Set the [[Index]] internal slot of resolveElement to index.
    11. Set the [[Values]] internal slot of resolveElement to values.
    12. Set the [[Capabilities]] internal slot of resolveElement to promiseCapabilities.
    13. Set the [[RemainingElements]] internal slot of resolveElement to remainingElementsCount.
    14. Set remainingElementsCount.[[value]] to remainingElementsCount.[[value]] + 1.
    15. Let result be Invoke(nextPromise, "then", (resolveElement, promiseCapability.[[Reject]])).
    16. IfAbruptRejectPromise(result, promiseCapability).
    17. Set index to index + 1.

Note: The all function requires its this value to be a constructor function that supports the parameter conventions of the Promise constructor.

Promise.all Resolve Element Functions

A Promise.all resolve element function is an anonymous built-in function that is used to resolve a specific Promise.all element. Each Promise.all resolve element function has [[Index]], [[Values]], [[Capabilities]], [[RemainingElements]], and [[AlreadyCalled]] internal slots.

When a Promise.all resolve element function F is called with argument x, the following steps are taken:

  1. If the value of F's [[AlreadyCalled]] internal slot is true, then return undefined.
  2. Set the [[AlreadyCalled]] internal slot of F to true.
  3. Let index be the value of F's [[Index]] internal slot.
  4. Let values be the value of F's [[Values]] internal slot.
  5. Let promiseCapability be the value of F's [[Capabilities]] internal slot.
  6. Let remainingElementsCount be the value of F's [[RemainingElements]] internal slot.
  7. Let result be CreateDataProperty(values, ToString(index), x).
  8. IfAbruptRejectPromise(result, promiseCapability).
  9. Set remainingElementsCount.[[value]] to remainingElementsCount.[[value]] - 1.
  10. If remainingElementsCount.[[value]] is 0,
    1. Return the result of calling the [[Call]] internal method of promiseCapability.[[Resolve]] with undefined as thisArgument and (values) as argumentsList.
  11. Return undefined.

Promise.prototype

The initial value of Promise.prototype is the Promise prototype object.

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }.

Promise.race ( iterable )

The race function returns a new promise which is settled in the same way as the first passed promise to settle. It resolves all elements of the passed iterable to promises as it runs this algorithm.

  1. Let C be the this value.
  2. Let promiseCapability be NewPromiseCapability(C).
  3. ReturnIfAbrupt(promiseCapability).
  4. Let iterator be GetIterator(iterable).
  5. IfAbruptRejectPromise(iterator, promiseCapability).
  6. Repeat
    1. Let next be IteratorStep(iterator).
    2. IfAbruptRejectPromise(next, promiseCapability).
    3. If next is false, return promiseCapability.[[Promise]].
    4. Let nextValue be IteratorValue(next).
    5. IfAbruptRejectPromise(nextValue, promiseCapability).
    6. Let nextPromise be Invoke(C, "resolve", (nextValue)).
    7. IfAbruptRejectPromise(nextPromise, promiseCapability).
    8. Let result be Invoke(nextPromise, "then", (promiseCapability.[[Resolve]], promiseCapability.[[Reject]])).
    9. IfAbruptRejectPromise(result, promiseCapability).

Note: The race function requires its this value to be a constructor function that supports the parameter conventions of the Promise constructor. It also requires that its this value provides a resolve method.

Promise.reject ( r )

The reject function returns a new promise rejected with the passed argument.

  1. Let C be the this value.
  2. Let promiseCapability be NewPromiseCapability(C).
  3. ReturnIfAbrupt(promiseCapability).
  4. Let rejectResult be the result of calling the [[Call]] internal method of promiseCapability.[[Reject]] with undefined as thisArgument and (r) as argumentsList.
  5. ReturnIfAbrupt(rejectResult).
  6. Return promiseCapability.[[Promise]].

Note: The reject function requires its this value to be a constructor function that supports the parameter conventions of the Promise constructor.

Promise.resolve ( x )

The resolve function returns a new promise resolved with the passed argument, or returns the argument if it is already a promise branded with the correct type.

  1. Let C be the this value.
  2. If IsPromise(x) is true,
    1. Let constructor be the value of x's [[PromiseConstructor]] internal slot.
    2. If SameValue(constructor, C) is true, return x.
  3. Let promiseCapability be NewPromiseCapability(C).
  4. ReturnIfAbrupt(promiseCapability).
  5. Let resolveResult be the result of calling the [[Call]] internal method of promiseCapability.[[Resolve]] with undefined as thisArgument and (x) as argumentsList.
  6. ReturnIfAbrupt(resolveResult).
  7. Return promiseCapability.[[Promise]].

Note: The resolve function requires its this value to be a constructor function that supports the parameter conventions of the Promise constructor.

Promise [ @@create ] ( )

The @@create method of a Promise function object F performs the following steps:

  1. Let F be the this value.
  2. Return AllocatePromise(F).

The value of the name property of this function is "[Symbol.create]".

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.

AllocatePromise ( constructor )

The abstract operation AllocatePromise allocates a new promise object using the constructor argument.

  1. Let obj be OrdinaryCreateFromConstructor(constructor, "%PromisePrototype%", ([[PromiseState]], [[PromiseConstructor]], [[PromiseResult]], [[PromiseFulfillReactions]], [[PromiseRejectReactions]])).
  2. Set obj's [[PromiseConstructor]] internal slot to constructor.
  3. Return obj.

Properties of the Promise Prototype Object

The value of the [[Prototype]] internal slot of the Promise prototype object is the standard built-in Object prototype object. The Promise prototype object is an ordinary object. It does not have a [[PromiseState]] internal slot or any of the other internal slots of Promise instances.

Promise.prototype.catch ( onRejected )

When the catch method is called with argument onRejected the following steps are taken:

  1. Let promise be the this value.
  2. Return Invoke(promise, "then", (undefined, onRejected)).

Promise.prototype.constructor

The initial value of Promise.prototype.constructor is the standard built-in Promise constructor.

Promise.prototype.then ( onFulfilled , onRejected )

When the then method is called with arguments onFulfilled and onRejected the following steps are taken:

  1. Let promise be the this value.
  2. If IsPromise(promise) is false, throw a TypeError exception.
  3. If IsCallable(onFulfilled) is false, then
    1. Let onFulfilled be "Identity".
  4. If IsCallable(onRejected) is false, then
    1. Let onRejected be "Thrower".
  5. Let C be Get(promise, "constructor").
  6. ReturnIfAbrupt(C).
  7. Let promiseCapability be NewPromiseCapability(C).
  8. ReturnIfAbrupt(promiseCapability).
  9. Let fulfillReaction be the PromiseReaction { [[Capabilities]]: promiseCapability, [[Handler]]: onFulfilled }.
  10. Let rejectReaction be the PromiseReaction { [[Capabilities]]: promiseCapability, [[Handler]]: onRejected }.
  11. If the value of promise's [[PromiseState]] internal slot is "pending",
    1. Append fulfillReaction as the last element of the List that is the value of promise's [[PromiseFulfillReactions]] internal slot.
    2. Append rejectReaction as the last element of the List that is the value of promise's [[PromiseRejectReactions]] internal slot.
  12. Else if the value of promise's [[PromiseState]] internal slot is "fulfilled",
    1. Let value be the value of promise's [[PromiseResult]] internal slot.
    2. Call EnqueueTask("PromiseTasks", PromiseReactionTask, (fulfillReaction, value)).
  13. Else if the value of promise's [[PromiseState]] internal slot is "rejected",
    1. Let reason be the value of promise's [[PromiseResult]] internal slot.
    2. Call EnqueueTask("PromiseTasks", (rejectReaction, reason)).
  14. Return promiseCapability.[[Promise]].

Promise.prototype [ @@toStringTag ]

The initial value of the @@toStringTag property is the string value "Promise".

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.

Properties of Promise Instances

Promise instances are ordinary objects that inherit properties from the Promise prototype object (the intrinsic, %PromisePrototype%). Promise instances are initially created with the internal slots described in this table.

Internal Slots of Promise Instances
Internal Slot Description
[[PromiseState]] A string value that governs how a promise will react to incoming calls to its then method. The possible values are: undefined, "pending", "fulfilled", and "rejected".
[[PromiseConstructor]] The function object that was used to construct this promise. Checked by the resolve method of the Promise constructor.
[[PromiseResult]] The value with which the promise has been fulfilled or rejected, if any. Only meaningful if [[PromiseState]] is not "pending".
[[PromiseFulfillReactions]] A List of PromiseReaction records to be processed when/if the promise transitions from the "pending" state to the "fulfilled" state.
[[PromiseRejectReactions]] A List of PromiseReaction records to be processed when/if the promise transitions from the "pending" state to the "rejected" state.

Deltas to Other Areas of the Spec

Well-Known Intrinsic Objects Table

Add the following rows:

%Promise% The initial value of the global object property named "Promise".
%PromisePrototype% The initial value of the "prototype" data property of the intrinsic %Promise%.

CC0
To the extent possible under law, Domenic Denicola has waived all copyright and related or neighboring rights to promises-unwrapping.

This work is published from:
<span property="vcard:Country" datatype="dct:ISO3166" content="US" about="http://domenicdenicola.com">
  United States
</span>.

promises-unwrapping's People

Contributors

annevk avatar domenic avatar forbeslindesay avatar mounirlamouri avatar timwienk avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

promises-unwrapping's Issues

Can sub-classes use additional arguments for "then"?

I'm writing a Promise sub-class that supports the resolver sending "progress" to listeners. e.g. my resolver accepts a third argument -- a notify function -- that is used to send "progress".

At the moment I register a listener by calling promise.then(null, null, onProgress) where onProgress is a function that expects a ProgressEvent.

Is this going to be supported or is the contract for then to only accept two arguments -- onFulfilled and onRejected?

Allow thenables

Introduce an abstract IsThenable or GetThen or similar and use it.

CallHandle improperly transforms a derived promise.

It seems that when a Promise is fulfilled or rejected, the CallHandle will call the proper fulfill or reject handler on the derived Promise, but it doesn't seem to be aware of which handler it is calling and will always set the derived Promise state to fulfilled, even though the origin Promise is rejected.

Example code:

var p = [];
p.push(new Promise(function(resolve, reject) { reject() }))
p.push(p[0].then(function() { console.log('fulfilled') }, function() { console.log('rejected') }))
p.push(p[1].then(function() { console.log('fulfilled') }, function() { console.log('rejected') }))

This will produce the following output:

rejected
fulfilled

And the states of each Promise are as follows:

p[0] = {
    [[Reason]]: undefined,
    [[Value]]: Unset
}
p[1] = {
    [[Reason]]: Unset,
    [[Value]]: undefined
}
p[2] = {
    [[Reason]]: Unset,
    [[Value]]: undefined
}

Make Resolve operate the same on promises and thenables, using `then`

Proposal

  • Remove special-casing of IsPromise in Resolve. Instead, do one-level thenable unwrapping there. That is:
  • Upon calling schedule a microtask do the usual get-then, call-then, dance.
  • The details here are a bit complicated but we should take whatever we get called back with, and do no more unwrapping beyond that first level.
  • Promise.prototype.then still does recursive unwrapping.

Observable Changes

  • This removes the internal state introspection of true promises done by the current Resolve algorithm, instead using the other true-promise's then:

    const p = new Promise(r => r(1));
    p.then = f => f(2);
    Promise.resolve(p).then(x => console.log(x)); // logs 2 now

    See related #53.

  • This makes overriding then in a promise subclass do what you expect when you return the promise:

    class InstrumentedPromise extends Promise {
        then(...args) {
            console.log("called then!");
            return super(...args);
        }
    }
    
    const instrumented = new InstrumentedPromise(r => r("instrumented value"));
    
    Promise.resolve(5).then(() => p).then(x => console.log(x));
    
    // Before this change, would only log "instrumented value".
    // Now, logs "called then!" then "instrumented value".
  • Implementations now make an observable call to then whenever a promise is resolved with another true promise, whereas previously they reached into its internal state.

Other Concerns

  • This seems to give a nice simplification and decoupling, making the internal data properties used only for tracking of internal state and not for cross-promise communication.
  • This should not impact monadic promise plans as we only do one-level unwrapping; hypothetical monadic promises for promises for promises will be turned into monadic promises for promises, allowing flatMap to retrieve the inner promise.

Replace "thenable" with "promise-like"?

As much as "thenable" has served us well in the promise community, for an ES-spec, the notion of "array-like" gives us a good precedence. It also helps overcome some peoples' confusion at the concept. We should probably adopt it.

@erights, I know you were a fan of thenable (actually you were the one that helped Kris and I realize we should adopt it more formally in our precise language). Any objections?

Throw Error if constructor passed to GetDeferred doesn't pass functions?

From GetDeferred:

  1. If IsConstructor(C),
    1. Let resolver be an ECMAScript function that:
      1. Lets resolve be the value resolver is passed as its first argument.
      2. Lets reject be the value resolver is passed as its second argument.
    2. Let promise be C.[[Construct]]((resolver)).

The first two arguments passed to resolver are expected to be functions, however no validation is done. Should there be an error thrown if resolve or reject aren't functions? Another option would be to fall back to use the default Promise constructor if they're not functions.

Bad promise constructor arguments

Assuming #8 is implemented and Promise(x) (without new) no longer coerces, what should the following do?

  1. Promise("5")
  2. Promise(() => {})
  3. new Promise("5")

I am leaning toward "throw a TypeError" but an argument could be made for returning a new promise rejected with a TypeError instead.

Formalize ThenableCoercions Weak Map

The ES-type notation at the very least is not going to fly. It might suffice to just define three abstract operations, ThenableCoercionsHas(thenable), ThenableCoercionsGet(thenable), and ThenableCoercionsSet(thenable, promise).

Specifying their behavior also needs to get a bit better. For example, it should probably be a per-realm weak map. Perhaps we associate a [[ThenableCoercions]] internal property %ThenableCoercions% intrinsic to the realm's global, then treat it like a [[WeakMapData]].

The actual weakness can be explained in a line or two of prose referring to weak map objects.

"Call `deferred.[[Resolve]](x)`" is imprecise and problematic

Since deferred.[[Resolve]] is derived from user-created constructors, it could be a non-function.

We should model this after how propDesc.[[Get]] is called:

  1. Otherwise, IsAccessorDescriptor(desc) must be true so, let getter be desc.[[Get]].

  2. If getter is undefined, return undefined.

  3. Return the result of calling the [[Call]] internal method of getter with Receiver as the thisArgument and an empty List as argumentsList.

Remove race() method

It seems that the any() static method from the DOM Promise has been replaced by race() which is basically the same behaviour with a different name.

The change has been made following the discussion in issue #13. Basically, the problem being that any() was confusing because it might mean "as soon as one promise settle" or "as soon as one promise fulfil or all reject". @domenic proposed to use the term race() to remove the ambiguity.

However, as @wasabiz pointed, adding race() seems to contradict the goal to have a minimalistic core. This method isn't a commonly used name and the behaviour is pretty simple to implement as needed. If the entire story around some(), any(), race() is not clear yet it seems that the best thing to do would be to not include this feature and see how things go. At least, in a Web API context, I would propose that but maybe in ES things are a bit different.

Obviously, if there are clear data showing that race() fulfil a common use case, all of that should be ignored ;)

Don't coerce Promise in UpdateDerived

Would it not be more favorable update with a derived promise when originator.[[Value]] is already a Promise rather than try to coerce it as a Thenable/Promise-like.

Promise(resolver) vs .then(resolve, reject)

As a developer I find the disconnect between the constructor and .then() functions puzzling and annoying.

The constructor take an object as an argument with properties .resolve and .reject; then() takes two arguments called resolve and reject.

Calling the current constructor with a syntax consistent with then() results in a very puzzling runtime error message deep in the Promise library. Definitely not ergonomic.

Add shorthand "prose hooks" for performing various operations

People seem confused, and want to know how they can do Promise.reject or Promise.all in their specs. It's pretty straightforward; you say:

Let x be the result of Promise.reject(r), using the initial value of Promise.reject.

But we may want to provide some easy phrases that are shorthand for this longhand. Here's what I can think of:

  • a promise resolved with x (e.g. "return a promise resolved with x," "let p be a promise resolved with x")
  • a promise rejected with r
  • cast x to a promise
  • let p be a newly-created promise object (the ES spec already uses this as shorthand for some crazy @@create stuff)
  • resolve p with x
  • reject p with r
  • let p be the result of (racing p1, p2, p3 / racing iterableOfPromises)
  • let p be the result of waiting for all of (p1, p2, p3 / iterableOfPromises) (any better phrasing?)

Then call to GetDeferred expects a proper Promise (or subclass) but doesn't verify

This is pretty out there, but the call to GetDeferred inside Then is the only place where GetDeferred is called and the [[Resolve]] and [[Reject]] return values are ignored. The assumption is made here that since Then only ever accepts true Promises (or subclasses) as an argument (p) that its constructor will create an object which is also a true Promise (passes IsPromise).

Here's a simple counterexample to this assumption (I think):

class SubPromise extends Promise { }

var sp = new SubPromise(resolve => {
    setTimeout(() => resolve('foo'), 2000);
});

Object.defineProperty(sp, 'constructor', {
    value(resolver) {
        var noop = () => { };
        resolver(noop, noop);
    }
});

var sp2 = sp.then(value => {
    console.log(value);
    return 'bar';
});

As far as I can tell, this will wait 2 seconds before failing the assertion in step 1 of SetValue (asserting that [[HasValue]] and [[HasReason]] are both false -- they'll actually not be set because sp2 isn't a true Promise).

An alternative situation that could cause this error would be a constructor that subclasses Promise but sometimes returns a promise and sometimes returns another value.

This error could be caught earlier by ensuring that the [[Promise]] value returned by GetDeferred is actually a true Promise. Alternatively, the [[Resolve]] and [[Reject]] functions returned by GetDeferred could be passed around to UpdateDerivedFromPromise so that whatever value the constructor created could try to be properly resolved with the first and second arguments it provided to its resolver function when it was created in GetDeferred with the C constructor (in case the constructor provides a true Promise sometimes and some other kind of Promise-like thenable other times).

Formalize creating functions that perform abstract operations

This occurs with some frequency throughout the spec. The simpler cases are currently in the form:

Let resolve(x) be an ECMAScript function that calls Resolve(p, x).

A more complicated case is:

Let resolver be an ECMAScript function that:

  1. Lets resolve be the value resolver is passed as its first argument.
  2. Lets reject be the value resolver is passed as its second argument.

And Promise.all has an even more complicated one.


The ES6 spec does not create functions and pass them to user code very often. When I asked @allenwb about this, he pointed me to the sole example of the strict-mode function.caller poison pill. The machinery invoked is somewhat formidable:

The %ThrowTypeError% object is a unique function object that is defined once for each Realm as follows:

  1. Assert: %FunctionPrototype% for the current Realm has already been initialized.
  2. Let functionPrototype be the intrinsic object %FunctionPrototype%.
  3. Let scope be the Global Environment.
  4. Let formalParameters be the syntactic production: FormalParameters : [empty] .
  5. Let body be the syntactic production: FunctionBody : ThrowTypeError .
  6. Let F be the result of performing FunctionAllocate with argument functionPrototype.
  7. Let %ThrowTypeError% be F.
  8. Perform the abstract operation FunctionInitialise with arguments F, Normal, formalParameters, body, scope, and true.
  9. Call the [[PreventExtensions]] internal method of F.

The ThrowTypeError syntactic production then has to manifest under Function Definitions, with syntax:

Supplemental Syntax

The following productions are used as an aid in specifying the semantics of certain ECMAScript language features. They are not used when parsing ECMAScript source code.

FunctionBody :
    ThrowTypeError
ThrowTypeError :
    [empty]

and runtime semantics under the subheading [Runtime Semantics: EvaluateBody](Runtime Semantics: EvaluateBody):

FunctionBody : ThrowTypeError

  1. Throw a TypeError exception.

I would prefer not to have to invoke all the above machinery, changing all those different places in the spec, if at all possible. I could wrap up most of the steps in the %ThrowTypeError% definition into a reusable function-creator, but the function body specification---the most important part---would be quite difficult.

At this point I'd love some help from @allenwb on how we can abstract this into something reusable but also of sufficient formality. Our existing language is very imprecise, not specifying the function's prototype, normal vs. method vs. arrow status, scope, length, and so on.

Converting Exceptions to Rejections in Initializer

Apologies if I'm retreading old ground, but under Promise(resolver), step 10 indicates that exceptions thrown by the initializer function must be converted to a rejection of the new promise. This seems surprising to me:

var promise = new Promise((resolve, reject) => {
    throw new Error("boom");
});

console.log("Should I see this?");

The initializer executes synchronously, and really just provides a closure around the resolve and reject parameters. It's more akin to a block than a promise transform. What are the arguments in favor of converting exceptions?

Thanks!

Why shouldn't promise-returning functions throw?

The spec-writing guide says that promise-returning functions should never throw; instead, they should just reject the returned promise with the relevant error.

It even gives a specific example of argument-parsing errors. Why is this? In existing callback functions, argument-parsing is usually an immediate thrown error, rather than calling the errback. Some types of argument-parsing errors aren't even handled by the specs - they're handled automatically by WebIDL.

I definitely understand why "content" errors should always happen in the promise, even if they can be detected "early enough" to throw synchronously instead. But argument syntax errors seem like a separate class to me.

As a further argument, getting a syntax error from an argument list is sometimes used as a test for support for some new functionality added to the function. Requiring the test to wait for its rejection handler to tell whether the new functionality is supported or not seems annoying.

Use bold, italics, and monospace separately

Currently I just use monospace. The ES spec uses each for different purposes, and some of the things that I use monospace for (like abstract operations) it just leaves as normal text.

Drop dot notation for internal data properties

See https://mail.mozilla.org/pipermail/es-discuss/2013-October/033962.html . Specifically Allen's statement "The dot notation is never used in the spec to refer to internal data properties."

Example from current draft (taken from IsPromise):

Return true if IsObject(x) and x.[[IsPromise]] is true.

I don't know what the correct notation would be, but [[IsPromise]] is an internal data property, so should probably not be accessed with dot notation.

This may have just been a notational convenience and something you intended to change later, but I didn't see a ticket for it so thought I would file one to help catch it early rather than later.

Great job so far, by the way!

Testable implementation is starting to lag

As of 19318d3 it is not up to date with the spec, as it does not handle exceptions in Promise.race per the new behavior. Also, as discovered in #42, internal properties are not inherited, so the way they are currently done is wrong. And the @@create stuff was never quite right.

As #6 is implemented, the delta between how the spec talks about things (with completion values) and how the testable implementation does (by not delving to that level) will grow. So I'll take a pause on updating the testable implementation alongside the spec. Once things settle, especially #6, I will go back and re-do it.

  • @@create vs. constructor semantics are too fake
  • Internal properties should not be inherited; currently scheme is too simple.
  • Completion values are not handled
  • Make sure all the tests still pass with the updated implementation

Typo: e => result

In the latest changes, one of the es that were changed to result got left behind.

In Promise ( resolver ), step 13:

If result is an abrupt completion, call Reject(promise, e.[[value]]).

should be

If result is an abrupt completion, call Reject(promise, result.[[value]]).

Promise.prototype.done

With current design, the only way to process resolved value and be sure that unhandled exceptions are exposed, is via following

promise.then(function (value) {
  setTimeout(function () {
    // Process value
   }, 0);
}, function (err) {
  setTimeout(function () {
    // Handle error
   }, 0);
});

Which is poor solution for many reasons:

  • Affects performance:
    • Creates promise objects we don't need
    • forces processing to further tick
  • Unintuitive
  • Verbose

In many promise implementations, there's already promise.done, which doesn't create any new promise, and invokes callbacks naturally (outside of try/catch clause).

As done cannot be implemented on top of available API, I think it's very important to include it in spec.

As side note, why do Promise.prototype.catch is specified? It can be very easily configured on top of the rest of the API, and it's usability is low.

Overriden `then`s?

Hoping for feedback by @erights especially on this issue raised by @wycats.

As specced, we do one-level unwrapping of true promises in Resolve. That is, we transfer over [[Following]], [[Value]], and [[Reason]]. In contrast, thenables get stored in [[Value]], and only unwrapped later, inside UpdateDerived (via Then).

However, this one-level unwrapping is somewhat "magic". In particular, it ignores overriden then methods, e.g.:

var p = new Promise(() => {});
p.then = f => f(5);

var q = new Promise(resolve => resolve(p));

// q is forever-pending, instead of fulfilled with 5.

This is a bit odd. Even worse, overwritten thens can "fool" (in some sense) Promise.cast:

Promise.cast(p).then(x => console.log(x)); // logs 5, synchronously

Lest you think the fix is just to make then non-configurable, also consider the case

var p2 = Object.create(new Promise(() => {}));
p2.then = f => f(5);

This p2 is just as bad as p, slipping through all our IsPromise checks, while behaving badly with its synchronous-then and unexpected behavior when used as an argument to resolve.


Site note: recall that the one-level unwrapping exists mainly for efficiency, as @erights pointed out on es-discuss. Otherwise we would just store the promise in [[Value]] like we do the thenables. (I think this would lead to killing [[Following]] as well.)

But even if we moved the unwrapping totally over to the then side, that would still leave the question of how to unwrap the overwritten-then promise: using its overwritten then, or reaching into its internal state as we do now.


Background note: @wycats's desire, which I do not really share, is that thenables should be able to fully participate in the adopt-internal-properties assimilation path. If I recall correctly, he envisions unique symbols for [[Following]], [[Value]], and [[Reason]]. In particular, he doesn't like it when one promise reaches into another promise's internal state, saying that it should work through the public API to do so instead, so that promises and non-promise thenables are on the same level playing field. He then brought up the overwritten-then case, which highlights the specific way in which promise objects (i.e. those created via Promise[@@create]()) are not on the same playing field as thenables. I pointed out that they were not supposed to be, since real promises were supposed to be high integrity, but then realized that because of "attacks" like the above, we don't really have a good way of guaranteeing high integrity promises.

consider a version of Promise.all that works on object

Promise.all takes an array of promises and returns a promise for an array.

This form of doing parallel execution is useful.

Another form of parallel execution that is useful is something that takes an object of key to promise and returns a promise for an object of key to value of promise at that key.

The majority of my parallel execution flow control is covered by a user land module called continuable-para that supports those two syntaxes. (the third syntax can be done with ES6 splat notation).

It would be a bit weird to have to use a 3rd party module for the object literal style parallel execution and use the browsers Promise.all for the array version.

Promise.prototype.finally

I am not sure why this wasn't in the original DOM spec, nor in @erights's concurrency strawman, but it's damn useful and not trivial to implement yourself.

Promise.prototype.finally = function (callback) {
    return this.then(
        value => this.constructor.resolve(callback()).then(() => value),
        reason => this.constructor.resolve(callback()).then(() => { throw reason; })
    );
};

Notably, like JS finally clause:

  • no value or reason is passed in to the finally code (i.e. to callback).
  • Does not affect the result, i.e. the resulting promise is still fulfilled with value or rejected with reason, just like the original one, unless...
  • If the finally code blows up (i.e. if callback throws, or returns a rejected promise), it propagates that failure onward, instead of the original success or failure.

Use cases collected so far:

  • Clean up event listeners, regardless of whether the promise succeeds or fails 1.
  • Hiding the spinner after a network request succeeds or fails 2.
  • Test teardown 3.

Handling of promises returned from onRejected

The spec currently doesn't appear to handle promises returned from onRejected in the way that most promises implementations/specs i'm familiar with do (including Promises/A+, WinJS and the previous DOM Futures spec).

xhr("example.com/a")
  .then(req => xhr("example.com/b"), err => xhr("example.com/default"))
  .then(req => console.log("completed with:" + req.responseText));

In this example, both the success and failure branches of the first then return promises. So the final promise should resolve only when the selected branch's promise is resolved/rejected.

By the current spec, I believe if the error branch is followed, the final promise will resolve with a Promise instead of a request object and will not wait on that promise completing.

Supporting promises returned from error handlers is useful for, among other things, error recovery - automatic retry with backoff on failure, etc. It also makes the API more consistent/predictable.

Was this an intentional change (if so, why?), or am I reading the spec wrong?

Tighten up internal data property treatment

Currently I use the concept of "set" and "unset." The correct verbiage is "has internal data property," e.g.

if x.[[Following]] is set

should become

if x has a [[Following]] internal data property.

Should we make subclassing easy via `this.constructor` (or similar)?

Disclaimer: this should not affect ability to achieve consensus, as it does not have observable effects until @@create is implemented in browsers.

@annevk pointed out that, unlike ES6 arrays, promises as specced are not very subclassable. If you do class MyPromise extends Promise {}, then every static method and instance method will by default return instances of Promise, not MyPromise.

This should probably be fixed to work in the same way as arrays, which create their new instances by saying "if this is an exotic array, use new this.constructor(0) to construct the returned thing."

Similarly, we can use "if this.[[IsPromise]] is true, use new this.constructor(() => {}) to construct the returned thing."


Relatedly, @allenwb noted in today's TC39 meeting that the pattern of new this.constructor(0) is a bit weird because of the implicit knowledge of the single-parameter form being special; @BrendanEich also was perturbed by the this.constructor lookup, as it is forgeable and (for arrays) a potential source of backward-incompatibility.

So, perhaps both promises and arrays could benefit from a hook for "get me a newly-created instance of this object's true, unforgable constructor."

Stop using function-call notation

The ES spec, unfortunately, prefers verbose things like

Return the result of calling the [[X]] internal method of y passing z and w as the arguments.

Whereas I have written things as

Return y.[[X]](z, w).

Never bypass the `then` method

Proposal

  • Move the contents of the Then abstract operation into the Promise.prototype.then method definition.
  • Everywhere we use the Then abstract operation, replace it with a call to the respective then method.
    • Promise.all
    • Promise.race
    • Promise.prototype.then's recursive case

Observable Changes

  • This makes overriden thens govern the behavior of a promise, e.g.

    const p = new Promise(() => {});
    p.then = f => f(5);
    Promise.all([p]).then(([x]) => console.log(x)); // logs 5
  • This forces implementations to make an observable call to then instead of using internal mechanisms. I imagine this will not actually be a burden.

  • This does not impact Promise.resolve yet, i.e.

    const p = new Promise(r => r(1));
    p.then = f => f(2);
    Promise.resolve(p).then(x => console.log(x)); // still logs 1 right now

    for that, see #54.

Formalize iteration protocol

In Promise.race and Promise.all I currently do

For each value nextValue of iterable,

I should use the new IteratorStep abstract operation.

Parameter to promise constructor

Per Promises/A+ (see also promises-aplus/constructor-spec#19) and for symmetry with then, the current spec does new Promise((resolve, reject) => ...). This matches Q, RSVP, and WinJS and is symmetric with then.

The Alex Russell Way of doing promise constructors would have this be new Promise(({ resolve, reject }) => ....

I see no reason to prefer the Alex Russell Way, but it is worth ensuring we get consensus. Using this issue to track any relevant debates.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.