Skip to content
This repository has been archived by the owner on Jan 26, 2022. It is now read-only.

[WIP] Add first spec draft #15

Merged
merged 8 commits into from
Mar 25, 2019
Merged
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 92 additions & 2 deletions spec.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
stage: 0
location: https://tc39.github.io/proposal-promise-any/
copyright: false
contributors: Mathias Bynens
contributors: Mathias Bynens & Sergey Rubanov
</pre>
<script src="ecmarkup.js" defer></script>
<link rel="stylesheet" href="ecmarkup.css">
Expand All @@ -32,4 +32,94 @@
}
</style>

TODO
<emu-clause id="sec-native-error-types-used-in-this-standard-aggregatenerror">
<h1>AggregateError</h1>
<p>TODO implement</p>
</emu-clause>

<emu-intro id="intro">
<h1>Introduction</h1>
<p>`Promise.any()` accepts an array of promises and returns a promise that is fulfilled by the first given promise to be fulfilled, or rejected with an array of rejection reasons if all of the given promises are rejected.</p>
</emu-intro>

<emu-clause id="sec-promise.allSettled">
<h1>Promise.any ( _iterable_ )</h1>
<p>The `any` function returns a promise that is fulfilled by the first given promise to be fulfilled, or rejected with an array of rejection reasons if all of the given promises are rejected. It resolves all elements of the passed iterable to promises as it runs this algorithm.</p>
<emu-alg>
1. Let _C_ be the *this* value.
1. If Type(_C_) is not Object, throw a *TypeError* exception.
1. Let _promiseCapability_ be ? NewPromiseCapability(_C_).
1. Let _iteratorRecord_ be GetIterator(_iterable_).
1. IfAbruptRejectPromise(_iteratorRecord_, _promiseCapability_).
1. Let _result_ be PerformPromiseAny(_iteratorRecord_, _C_, _promiseCapability_).
1. If _result_ is an abrupt completion, then
1. If _iteratorRecord_.[[Done]] is *false*, set _result_ to IteratorClose(_iteratorRecord_, _result_).
1. IfAbruptRejectPromise(_result_, _promiseCapability_).
1. Return Completion(_result_).
</emu-alg>
<p>This function is the <dfn>%Promise_any%</dfn> intrinsic object.</p> <!-- not sure about this -->
chicoxyzzy marked this conversation as resolved.
Show resolved Hide resolved
<emu-note>
<p>The `any` function requires its *this* value to be a constructor function that supports the parameter conventions of the `Promise` constructor.</p>
</emu-note>

<emu-clause id="sec-performpromiseany" aoid="PerformPromiseAny">
<h1>Runtime Semantics: PerformPromiseAny ( _iteratorRecord_, _constructor_, _resultCapability_ )</h1>
<p>When the PerformPromiseAny abstract operation is called with arguments _iteratorRecord_, _constructor_, and _resultCapability_, the following steps are taken:</p>
<emu-alg>
1. Assert: ! IsConstructor(_constructor_) is *true*.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add an assertion about iteratorRecord?

1. Assert: _resultCapability_ is a PromiseCapability Record.
1. Let _values_ be a new empty List.
1. Let _remainingElementsCount_ be a new Record { [[Value]]: 1 }.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems weird to have a record here and pass it around. Is keeping a count like this the only solution?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at existing ECMAScript Specification Types, Record is most suitable type here. It's used in other Promise namespace functions as well.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh sure, i wasn't suggesting a JS object or anything :-) more that, is passing around a counter the only viable approach?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I got it. Not sure to be honest 🤔 I need to do some more research to answer this question 🕵️‍♀️

1. Let _index_ be 0.
1. Repeat,
1. Let _next_ be IteratorStep(_iteratorRecord_).
1. If _next_ is an abrupt completion, set _iteratorRecord_.[[Done]] to *true*.
1. ReturnIfAbrupt(_next_).
1. If _next_ is *false*, then
1. Set _iteratorRecord_.[[Done]] to *true*.
1. Set _remainingElementsCount_.[[Value]] to _remainingElementsCount_.[[Value]] - 1.
1. If _remainingElementsCount_.[[Value]] is 0, then
1. Let _valuesArray_ be CreateArrayFromList(_values_).
1. Perform ? Call(_resultCapability_.[[Resolve]], *undefined*, &laquo; _valuesArray_ &raquo;).
1. Return _resultCapability_.[[Promise]].
1. Let _nextValue_ be IteratorValue(_next_).
1. If _nextValue_ is an abrupt completion, set _iteratorRecord_.[[Done]] to *true*.
1. ReturnIfAbrupt(_nextValue_).
1. Append *undefined* to _values_.
1. Let _nextPromise_ be ? Invoke(_constructor_, `"resolve"`, &laquo; _nextValue_ &raquo;).
1. Let _steps_ be the algorithm steps defined in <emu-xref href="#sec-promise.any-reject-element-functions" title></emu-xref>.
1. Let _rejectElement_ be CreateBuiltinFunction(_steps_, &laquo; [[AlreadyCalled]], [[Index]], [[Values]], [[Capability]], [[RemainingElements]] &raquo;).
1. Set _rejectElement_.[[AlreadyCalled]] to a new Record { [[Value]]: *false* }.
1. Set _rejectElement_.[[Index]] to _index_.
1. Set _rejectElement_.[[Values]] to _values_.
1. Set _rejectElement_.[[Capability]] to _resultCapability_.
1. Set _rejectElement_.[[RemainingElements]] to _remainingElementsCount_.
1. Set _remainingElementsCount_.[[Value]] to _remainingElementsCount_.[[Value]] + 1.
1. Perform ? Invoke(_nextPromise_, `"then"`, &laquo; _resultCapability_, _rejectElement_[[Reject]] &raquo;).
1. Increase _index_ by 1.
</emu-alg>
</emu-clause>

<emu-clause id="sec-promise.any-reject-element-functions">
<h1>`Promise.any` Reject Element Functions</h1>
<p>A `Promise.any` reject element function is an anonymous built-in function that is used to reject a specific `Promise.any` element. Each `Promise.any` reject element function has [[Index]], [[Values]], [[Capability]], [[RemainingElements]], and [[AlreadyCalled]] internal slots.</p>
<p>When a `Promise.any` reject element function is called with argument _x_, the following steps are taken:</p>
<emu-alg>
1. Let _F_ be the active function object.
1. Let _alreadyCalled_ be _F_.[[AlreadyCalled]].
1. If _alreadyCalled_.[[Value]] is *true*, return *undefined*.
1. Set _alreadyCalled_.[[Value]] to *true*.
1. Let _index_ be _F_.[[Index]].
1. Let _values_ be _F_.[[Values]].
1. Let _promiseCapability_ be _F_.[[Capability]].
1. Let _remainingElementsCount_ be _F_.[[RemainingElements]].
1. Set _values_[_index_] to _x_.
1. Set _remainingElementsCount_.[[Value]] to _remainingElementsCount_.[[Value]] - 1.
1. If _remainingElementsCount_.[[Value]] is 0, then
1. Let _valuesArray_ be CreateArrayFromList(_values_).
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably should be something like

        Let _valuesArray_ be AggregateError(_values_, ???).

I'm not sure

Copy link
Collaborator

@bakkot bakkot Mar 6, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't yet have a convention for how to specify an error object which has a required property. I think I would do something like

1. Let _errorsArray_ be CreateArrayFromList(_values_).
1. Let _exception_ be a newly created AggregateError object.
1. Perform ! CreateDataProperty(_exception_, `"errors"`, _errorsArray_).
1. Return ? Call(*undefined*, _promiseCapability_.[[Reject]], &laquo; _exception_ &raquo;).

The "a newly created WhateverError object" phrasing is used elsewhere. Doing it this way hopefully makes it clear that engines are required to provide .errors but are free to make message whatever they feel is appropriate, just as with other errors thrown by builtins.

1. Return ? Call(*undefined*, _promiseCapability_.[[Reject]], &laquo; _valuesArray_ &raquo;).
1. Return *undefined*.
</emu-alg>
<p>The `"length"` property of a `Promise.any` resolve element function is 1.</p>
</emu-clause>
</emu-clause>