├── .editorconfig ├── .gitignore ├── .nvmrc ├── .travis-github-deploy-key.enc ├── .travis.yml ├── README.md ├── package.json └── spec.html /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = tab 6 | end_of_line = lf 7 | insert_final_newline = true 8 | trim_trailing_whitespace = true 9 | 10 | [{README.md,package.json,spec.html,.travis.yml}] 11 | indent_style = space 12 | indent_size = 2 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json 2 | 3 | dist 4 | 5 | # Installed npm modules 6 | node_modules 7 | 8 | # Folder view configuration files 9 | .DS_Store 10 | Desktop.ini 11 | 12 | # Thumbnail cache files 13 | ._* 14 | Thumbs.db 15 | 16 | # Files that might appear on external disks 17 | .Spotlight-V100 18 | .Trashes 19 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 8 2 | -------------------------------------------------------------------------------- /.travis-github-deploy-key.enc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tc39/proposal-promise-any/5dadf6e54af38363fe341f75de88901a5c5f06d0/.travis-github-deploy-key.enc -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | after_success: 3 | - $(npm bin)/set-up-ssh --key "${encrypted_13071c2f6e86_key}" --iv "${encrypted_13071c2f6e86_iv}" 4 | --path-encrypted-key .travis-github-deploy-key.enc 5 | - $(npm bin)/update-branch --commands 'npm run build' --commit-message "Update gh-pages 6 | @ ${TRAVIS_COMMIT}" --directory 'dist' --distribution-branch 'gh-pages' --source-branch 7 | 'master' 8 | branches: 9 | only: 10 | - master 11 | env: 12 | global: 13 | secure: zKoQlRbPLo1vDZfbilVgf0z3lMRFvhPI7mwbI1ebWxeA9BIQ+4CquIf6y5/TRW2PUY6Faf8dfqIKoh7rnqaMI/XMoVIWlGMV+SQCyBAdffpoOGyRO5NRZrdeV/MqzTT/iOHANrDc9ymdMrpV5lOywaANQZyD96q6UMurGsBwSF3Wp08o3FykxkCqNmAxiU4Wgo3FxObSfJjy40dXr854zFJ8HwlBNo/D7nmuhGCHD3ss6nNreiZE+vcV3SGce+neiesW0AmC6J6w5qacpf2QQf7as+HxuP4b/vo8gSEM8Dl4nfWs+QEdHVgUu3zte2N7Jg/HpjbQD+3bKVdQi+FAPXN1ykbxSCFlbgXN95ds8gPBbXY1mx/OLoUcggQ8OmU1O9STCvT0Huzhj5gPoxZoWVXbkmPuGt6P1kbOBgXrM5R17d+gZbzrZ0MMTjbJp8kv0cjla7iyYk1FKCK1vpYyi2ph0mrNYBFN8vWFm2HFpAGaYBoVNw9PH6pCg36pr/2fg3rCfFD8ef6a6zDhRS5vKCaUWLcH4i8QQ8KDTwuXQVOe7GjiJp0Hx0S6cwad4LR+jiNe26A6eurmtN5K75WLERWjRRrdne2IIIC77xh5Whgs0uAAFiPK1BAZKX2zSKq4tMkiRaIpKz8FQHUaYNJVeZk6MIONK3GOIJoSw5w9Rs0= 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ECMAScript proposal: `Promise.any` + `AggregateError` 2 | 3 | **Author**: Mathias Bynens, Kevin Gibbons, Sergey Rubanov 4 | 5 | **Champion**: Mathias Bynens 6 | 7 | **Stage**: Stage 4 of [the TC39 process](https://tc39.es/process-document/). 8 | 9 | ## Motivation 10 | 11 | There are [four main combinators in the `Promise` landscape](https://v8.dev/features/promise-combinators). 12 | 13 | | name | description | | 14 | | -------------------- | ----------------------------------------------- | ------------------------------------- | 15 | | `Promise.allSettled` | does not short-circuit | added in ES2020 ✅ | 16 | | `Promise.all` | short-circuits when an input value is rejected | added in ES2015 ✅ | 17 | | `Promise.race` | short-circuits when an input value is settled | added in ES2015 ✅ | 18 | | `Promise.any` | short-circuits when an input value is fulfilled | this proposal 🆕 scheduled for ES2021 | 19 | 20 | These are all commonly available in userland promise libraries, and they’re all independently useful, each one serving different use cases. 21 | 22 | ## Proposed solution 23 | 24 | `Promise.any` accepts an iterable of promises and returns a promise that is fulfilled by the first given promise to be fulfilled, or rejected with an `AggregateError` holding the rejection reasons if all of the given promises are rejected. (If something more fundamental goes wrong, e.g. iterating over the iterable results in an exception, `Promise.any` returns a rejected promise with that exception.) 25 | 26 | ## High-level API 27 | 28 | ```js 29 | try { 30 | const first = await Promise.any(promises); 31 | // Any of the promises was fulfilled. 32 | } catch (error) { 33 | // All of the promises were rejected. 34 | } 35 | ``` 36 | 37 | Or, without `async`/`await`: 38 | 39 | ```js 40 | Promise.any(promises).then( 41 | (first) => { 42 | // Any of the promises was fulfilled. 43 | }, 44 | (error) => { 45 | // All of the promises were rejected. 46 | } 47 | ); 48 | ``` 49 | 50 | In the above examples, `error` is an `AggregateError`, a new `Error` subclass that groups together individual errors. Every `AggregateError` instance contains a pointer to an array of exceptions. 51 | 52 | ### FAQ 53 | 54 | #### Why choose the name `any`? 55 | 56 | It clearly describes what it does, and there’s precedent for the name `any` in userland libraries offering this functionality: 57 | 58 | - https://github.com/kriskowal/q#combination 59 | - http://bluebirdjs.com/docs/api/promise.any.html 60 | - https://github.com/m0ppers/promise-any 61 | - https://github.com/cujojs/when/blob/master/docs/api.md#whenany 62 | - https://github.com/sindresorhus/p-any 63 | 64 | #### Why throw an `AggregateError` instead of an array? 65 | 66 | The prevailing practice within the ECMAScript language is to only throw exception types. Existing code in the ecosystem likely relies on the fact that currently, all exceptions thrown by built-in methods and syntax are `instanceof Error`. Adding a new language feature that can throw a plain array would break that invariant, and could be a web compatibility issue. Additionally, by using an `Error` instance (or a subclass), a stack trace can be provided — something that’s easy to discard if not needed, but impossible to obtain later if it is needed. 67 | 68 | ## Illustrative examples 69 | 70 | This snippet checks which endpoint responds the fastest, and then logs it. 71 | 72 | ```js 73 | Promise.any([ 74 | fetch('https://v8.dev/').then(() => 'home'), 75 | fetch('https://v8.dev/blog').then(() => 'blog'), 76 | fetch('https://v8.dev/docs').then(() => 'docs') 77 | ]).then((first) => { 78 | // Any of the promises was fulfilled. 79 | console.log(first); 80 | // → 'home' 81 | }).catch((error) => { 82 | // All of the promises were rejected. 83 | console.log(error); 84 | }); 85 | ``` 86 | 87 | ## TC39 meeting notes 88 | 89 | - [March 2019](https://github.com/tc39/notes/blob/master/meetings/2019-03/mar-27.md#promiseany) 90 | - [June 2019](https://github.com/tc39/notes/blob/master/meetings/2019-06/june-5.md#promiseany) 91 | - [July 2019](https://github.com/tc39/notes/blob/master/meetings/2019-07/july-24.md#promiseany) 92 | - October 2019 [part one](https://github.com/tc39/notes/blob/master/meetings/2019-10/october-2.md#promiseany-for-stage-3) and [part two](https://github.com/tc39/notes/blob/master/meetings/2019-10/october-3.md#promiseany-reprise) 93 | - June 2020 [part one](https://github.com/tc39/notes/blob/master/meetings/2020-06/june-2.md#aggregateerror-errors-update) and [part two](https://github.com/tc39/notes/blob/master/meetings/2020-06/june-2.md#aggregateerror-constructor-update) 94 | - [July 2020](https://github.com/tc39/notes/blob/master/meetings/2020-07/july-21.md#promiseany--aggregateerror-for-stage-4) 95 | 96 | ## Specification 97 | 98 | - [Ecmarkup source](https://github.com/tc39/proposal-promise-any/blob/master/spec.html) 99 | - [HTML version](https://tc39.es/proposal-promise-any/) 100 | 101 | ## Implementations 102 | 103 | - JavaScript engines: 104 | - [JavaScriptCore](https://bugs.webkit.org/show_bug.cgi?id=202566), shipping in Safari 14 105 | - [SpiderMonkey](https://bugzilla.mozilla.org/show_bug.cgi?id=1568903), shipping in Firefox 79 106 | - [V8](https://bugs.chromium.org/p/v8/issues/detail?id=9808), shipping in Chrome 85 107 | - [XS](https://blog.moddable.com/blog/xs10/) 108 | - [engine262](https://github.com/engine262/engine262/commit/c68877ef1c4633daac8b58b5ce1876f709c1cc16) 109 | 110 | - Polyfills: 111 | - [core-js](https://github.com/zloirock/core-js#promiseany) 112 | - [es-shims](https://github.com/es-shims/Promise.any) 113 | 114 | - [TypeScript](https://github.com/microsoft/TypeScript/pull/33844) 115 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "test": ":", 5 | "build": "mkdir -p dist; ecmarkup --verbose spec.html dist/index.html --css dist/ecmarkup.css --js dist/ecmarkup.js" 6 | }, 7 | "devDependencies": { 8 | "@alrra/travis-scripts": "^3.0.1", 9 | "ecmarkup": "^3.25.3" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /spec.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
  4 | title: Promise.any
  5 | status: proposal
  6 | stage: 4
  7 | location: https://tc39.es/proposal-promise-any/
  8 | copyright: false
  9 | contributors: Mathias Bynens, Kevin Gibbons, Sergey Rubanov
 10 | 
11 | 18 | 19 | 20 | 21 | 22 |

Introduction

23 |

`Promise.any()` accepts an iterable of promises and returns a promise that is fulfilled by the first given promise to be fulfilled, or rejected with an `AggregateError` holding the rejection reasons if all of the given promises are rejected.

24 |
25 | 26 | 27 |

Well-Known Intrinsic Objects

28 |

Well-known intrinsics are built-in objects that are explicitly referenced by the algorithms of this specification and which usually have realm-specific identities. Unless otherwise specified each intrinsic object actually corresponds to a set of similar objects, one per realm.

29 |

Within this specification a reference such as %name% means the intrinsic object, associated with the current realm, corresponding to the name. Determination of the current realm and its intrinsics is described in . The well-known intrinsics are listed in .

30 | 31 | 32 | 33 | 34 | 37 | 40 | 43 | 44 | 45 | 48 | 51 | 54 | 55 | 56 | 59 | 62 | 65 | 66 | 67 |
35 | Intrinsic Name 36 | 38 | Global Name 39 | 41 | ECMAScript Language Association 42 |
46 | %AggregateError% 47 | 49 | `AggregateError` 50 | 52 | The `AggregateError` constructor () 53 |
57 | %AggregateErrorPrototype% 58 | 60 | `AggregateError.prototype` 61 | 63 | The initial value of the `prototype` data property of %AggregateError%; i.e., %AggregateError.prototype% 64 |
68 |
69 |
70 | 71 | 72 |

Error Objects

73 |

Instances of Error objects are thrown as exceptions when runtime errors occur. The Error objects may also serve as base objects for user-defined exception classes.

74 |

When an ECMAScript implementation detects a runtime error, it throws a new instance of one of the _NativeError_ objects defined in or a new instance of AggregateError object defined in . Each of these objects has the structure described below, differing only in the name used as the constructor name instead of _NativeError_, in the `name` property of the prototype object, in the implementation-defined `message` property of the prototype object, and in the presence of the %AggregateError%-specific `errors` property.

75 | 76 | 77 |

Properties of Error Instances

78 |

Error instances are ordinary objects that inherit properties from the Error prototype object and have an [[ErrorData]] internal slot whose value is *undefined*. The only specified uses of [[ErrorData]] is to identify Error, AggregateError, and _NativeError_ instances as Error objects within `Object.prototype.toString`.

79 |
80 | 81 | 82 |

Native Error Types Used in This Standard

83 |

A new instance of one of the _NativeError_ objects below or of the AggregateError object is thrown when a runtime error is detected. All of these objects share the same structure, as described in .

84 |
85 | 86 | 87 |

_NativeError_ Object Structure

88 |

For each error object, references to _NativeError_ in the definition should be replaced with the appropriate error object name from .

89 | 90 | 91 |

Properties of _NativeError_ Instances

92 |

_NativeError_ instances are ordinary objects that inherit properties from their _NativeError_ prototype object and have an [[ErrorData]] internal slot whose value is *undefined*. The only specified use of [[ErrorData]] is by `Object.prototype.toString` () to identify Error, AggregateError, or _NativeError_ instances.

93 |
94 |
95 | 96 | 97 |

AggregateError Objects

98 | 99 | 100 |

The AggregateError Constructor

101 |

The AggregateError constructor:

102 |
    103 |
  • is the intrinsic object %AggregateError%.
  • 104 |
  • is the initial value of the `AggregateError` property of the global object.
  • 105 |
  • creates and initializes a new AggregateError object when called as a function rather than as a constructor. Thus the function call `AggregateError(…)` is equivalent to the object creation expression `new AggregateError(…)` with the same arguments.
  • 106 |
  • is designed to be subclassable. It may be used as the value of an `extends` clause of a class definition. Subclass constructors that intend to inherit the specified AggregateError behaviour must include a `super` call to the AggregateError constructor to create and initialize subclass instances with an [[ErrorData]] and [[AggregateErrors]] internal slots.
  • 107 |
108 | 109 | 110 |

AggregateError ( _errors_, _message_ )

111 |

When the *AggregateError* function is called with arguments _errors_ and _message_, the following steps are taken:

112 | 113 | 1. If NewTarget is *undefined*, let _newTarget_ be the active function object, else let _newTarget_ be NewTarget. 114 | 1. Let _O_ be ? OrdinaryCreateFromConstructor(_newTarget_, `"%AggregateError.prototype%"`, « [[ErrorData]] »). 115 | 1. If _message_ is not _undefined_, then 116 | 1. Let _msg_ be ? ToString(_message_). 117 | 1. Let _msgDesc_ be the PropertyDescriptor { [[Value]]: _msg_, [[Writable]]: *true*, [[Enumerable]]: *false*, [[Configurable]]: *true* }. 118 | 1. Perform ! DefinePropertyOrThrow(_O_, *"message"*, _msgDesc_). 119 | 1. Let _errorsList_ be ? IterableToList(_errors_). 120 | 1. Perform ! DefinePropertyOrThrow(_O_, `"errors"`, Property Descriptor { [[Configurable]]: *true*, [[Enumerable]]: *false*, [[Writable]]: *true*, [[Value]]: ! CreateArrayFromList(_errorsList_) }). 121 | 1. Return _O_. 122 | 123 |
124 |
125 | 126 | 127 |

Properties of the AggregateError Constructor

128 |

The AggregateError constructor:

129 |
    130 |
  • has a [[Prototype]] internal slot whose value is the intrinsic object %Error%.
  • 131 |
  • has the following properties:
  • 132 |
133 | 134 | 135 |

AggregateError.prototype

136 |

The initial value of `AggregateError.prototype` is the intrinsic object %AggregateError.prototype%.

137 |

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

138 |
139 |
140 | 141 | 142 |

Properties of the AggregateError Prototype Object

143 |

The AggregateError prototype object:

144 |
    145 |
  • is the intrinsic object %AggregateError.prototype%.
  • 146 |
  • is an ordinary object.
  • 147 |
  • is not an Error instance or an AggregateError instance and does not have an [[ErrorData]] internal slot.
  • 148 |
  • has a [[Prototype]] internal slot whose value is the intrinsic object %Error.prototype%.
  • 149 |
150 | 151 | 152 |

AggregateError.prototype.constructor

153 |

The initial value of `AggregateError.prototype.constructor` is the intrinsic object %AggregateError%.

154 |

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

155 |
156 | 157 | 158 |

AggregateError.prototype.message

159 |

The initial value of `AggregateError.prototype.message` is the empty String.

160 |

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

161 |
162 | 163 | 164 |

AggregateError.prototype.name

165 |

The initial value of `AggregateError.prototype.name` is `"AggregateError"`.

166 |

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

167 |
168 |
169 | 170 | 171 |

Properties of AggregateError Instances

172 |

AggregateError instances are ordinary objects that inherit properties from their AggregateError prototype object and have an [[ErrorData]] internal slot whose value is *undefined*. The only specified use of [[ErrorData]] is by `Object.prototype.toString` () to identify Error, AggregateError, or _NativeError_ instances.

173 |
174 |
175 |
176 | 177 | 178 |

Promise.any ( _iterable_ )

179 |

The `any` function returns a promise that is fulfilled by the first given promise to be fulfilled, or rejected with an `AggregateError` holding the 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.

180 | 181 | 1. Let _C_ be the *this* value. 182 | 1. Let _promiseCapability_ be ? NewPromiseCapability(_C_). 183 | 1. Let _promiseResolve_ be GetPromiseResolve(_C_). 184 | 1. IfAbruptRejectPromise(_promiseResolve_, _promiseCapability_). 185 | 1. Let _iteratorRecord_ be GetIterator(_iterable_). 186 | 1. IfAbruptRejectPromise(_iteratorRecord_, _promiseCapability_). 187 | 1. Let _result_ be PerformPromiseAny(_iteratorRecord_, _C_, _promiseCapability_, _promiseResolve_). 188 | 1. If _result_ is an abrupt completion, then 189 | 1. If _iteratorRecord_.[[Done]] is *false*, set _result_ to IteratorClose(_iteratorRecord_, _result_). 190 | 1. IfAbruptRejectPromise(_result_, _promiseCapability_). 191 | 1. Return Completion(_result_). 192 | 193 | 194 |

The `any` function requires its *this* value to be a constructor function that supports the parameter conventions of the `Promise` constructor.

195 |
196 | 197 | 198 |

Runtime Semantics: PerformPromiseAny ( _iteratorRecord_, _constructor_, _resultCapability_, _promiseResolve_ )

199 |

When the PerformPromiseAny abstract operation is called with arguments _iteratorRecord_, _constructor_, _resultCapability_, and _promiseResolve_, the following steps are taken:

200 | 201 | 1. Assert: ! IsConstructor(_constructor_) is *true*. 202 | 1. Assert: _resultCapability_ is a PromiseCapability Record. 203 | 1. Assert: ! IsCallable(_promiseResolve_) is *true*. 204 | 1. Let _errors_ be a new empty List. 205 | 1. Let _remainingElementsCount_ be a new Record { [[Value]]: 1 }. 206 | 1. Let _index_ be 0. 207 | 1. Repeat, 208 | 1. Let _next_ be IteratorStep(_iteratorRecord_). 209 | 1. If _next_ is an abrupt completion, set _iteratorRecord_.[[Done]] to *true*. 210 | 1. ReturnIfAbrupt(_next_). 211 | 1. If _next_ is *false*, then 212 | 1. Set _iteratorRecord_.[[Done]] to *true*. 213 | 1. Set _remainingElementsCount_.[[Value]] to _remainingElementsCount_.[[Value]] - 1. 214 | 1. If _remainingElementsCount_.[[Value]] is 0, then 215 | 1. Let _error_ be a newly created `AggregateError` object. 216 | 1. Perform ! DefinePropertyOrThrow(_error_, `"errors"`, Property Descriptor { [[Configurable]]: *true*, [[Enumerable]]: *false*, [[Writable]]: *true*, [[Value]]: ! CreateArrayFromList(_errors_) }). 217 | 1. Return ThrowCompletion(_error_). 218 | 1. Return _resultCapability_.[[Promise]]. 219 | 1. Let _nextValue_ be IteratorValue(_next_). 220 | 1. If _nextValue_ is an abrupt completion, set _iteratorRecord_.[[Done]] to *true*. 221 | 1. ReturnIfAbrupt(_nextValue_). 222 | 1. Append *undefined* to _errors_. 223 | 1. Let _nextPromise_ be ? Call(_promiseResolve_, _constructor_, « _nextValue_ »). 224 | 1. Let _steps_ be the algorithm steps defined in . 225 | 1. Let _rejectElement_ be ! CreateBuiltinFunction(_steps_, « [[AlreadyCalled]], [[Index]], [[Errors]], [[Capability]], [[RemainingElements]] »). 226 | 1. Set _rejectElement_.[[AlreadyCalled]] to a new Record { [[Value]]: *false* }. 227 | 1. Set _rejectElement_.[[Index]] to _index_. 228 | 1. Set _rejectElement_.[[Errors]] to _errors_. 229 | 1. Set _rejectElement_.[[Capability]] to _resultCapability_. 230 | 1. Set _rejectElement_.[[RemainingElements]] to _remainingElementsCount_. 231 | 1. Set _remainingElementsCount_.[[Value]] to _remainingElementsCount_.[[Value]] + 1. 232 | 1. Perform ? Invoke(_nextPromise_, `"then"`, « _resultCapability_.[[Resolve]], _rejectElement_ »). 233 | 1. Increase _index_ by 1. 234 | 235 |
236 | 237 | 238 |

`Promise.any` Reject Element Functions

239 |

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]], [[Errors]], [[Capability]], [[RemainingElements]], and [[AlreadyCalled]] internal slots.

240 |

When a `Promise.any` reject element function is called with argument _x_, the following steps are taken:

241 | 242 | 1. Let _F_ be the active function object. 243 | 1. Let _alreadyCalled_ be _F_.[[AlreadyCalled]]. 244 | 1. If _alreadyCalled_.[[Value]] is *true*, return *undefined*. 245 | 1. Set _alreadyCalled_.[[Value]] to *true*. 246 | 1. Let _index_ be _F_.[[Index]]. 247 | 1. Let _errors_ be _F_.[[Errors]]. 248 | 1. Let _promiseCapability_ be _F_.[[Capability]]. 249 | 1. Let _remainingElementsCount_ be _F_.[[RemainingElements]]. 250 | 1. Set _errors_[_index_] to _x_. 251 | 1. Set _remainingElementsCount_.[[Value]] to _remainingElementsCount_.[[Value]] - 1. 252 | 1. If _remainingElementsCount_.[[Value]] is 0, then 253 | 1. Let _error_ be a newly created `AggregateError` object. 254 | 1. Perform ! DefinePropertyOrThrow(_error_, `"errors"`, Property Descriptor { [[Configurable]]: *true*, [[Enumerable]]: *false*, [[Writable]]: *true*, [[Value]]: ! CreateArrayFromList(_errors_) }). 255 | 1. Return ? Call(_promiseCapability_.[[Reject]], undefined, « _error_ »). 256 | 1. Return *undefined*. 257 | 258 |

The `"length"` property of a `Promise.any` reject element function is 1.

259 |
260 |
261 | 262 | 263 |

Runtime Semantics: IterableToList ( _items_ [ , _method_ ] )

264 |

The abstract operation IterableToList performs the following steps:

265 | 266 | 1. Let _iteratorRecord_ be ? GetIterator(_items_, ~sync~, _method_). 267 | 1. If _method_ is present, then 268 | 1. Let _iteratorRecord_ be ? GetIterator(_items_, ~sync~, _method_). 269 | 1. Else, 270 | 1. Let _iteratorRecord_ be ? GetIterator(_items_, ~sync~). 271 | 1. Let _values_ be a new empty List. 272 | 1. Let _next_ be *true*. 273 | 1. Repeat, while _next_ is not *false* 274 | 1. Set _next_ to ? IteratorStep(_iteratorRecord_). 275 | 1. If _next_ is not *false*, then 276 | 1. Let _nextValue_ be ? IteratorValue(_next_). 277 | 1. Append _nextValue_ to the end of the List _values_. 278 | 1. Return _values_. 279 | 280 |
281 | --------------------------------------------------------------------------------