| // Copyright 2012 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| (function(global, utils, extrasUtils) { |
| |
| "use strict"; |
| |
| %CheckIsBootstrapping(); |
| |
| // ------------------------------------------------------------------- |
| // Imports |
| |
| var InternalArray = utils.InternalArray; |
| var promiseHandledBySymbol = |
| utils.ImportNow("promise_handled_by_symbol"); |
| var promiseForwardingHandlerSymbol = |
| utils.ImportNow("promise_forwarding_handler_symbol"); |
| var GlobalPromise = global.Promise; |
| |
| // ------------------------------------------------------------------- |
| // Define exported functions. |
| |
| // Combinators. |
| |
| // ES#sec-promise.all |
| // Promise.all ( iterable ) |
| function PromiseAll(iterable) { |
| if (!IS_RECEIVER(this)) { |
| throw %make_type_error(kCalledOnNonObject, "Promise.all"); |
| } |
| |
| // false debugEvent so that forwarding the rejection through all does not |
| // trigger redundant ExceptionEvents |
| var deferred = %new_promise_capability(this, false); |
| var resolutions = new InternalArray(); |
| var count; |
| |
| // For catch prediction, don't treat the .then calls as handling it; |
| // instead, recurse outwards. |
| var instrumenting = DEBUG_IS_ACTIVE; |
| if (instrumenting) { |
| SET_PRIVATE(deferred.reject, promiseForwardingHandlerSymbol, true); |
| } |
| |
| function CreateResolveElementFunction(index, values, promiseCapability) { |
| var alreadyCalled = false; |
| return (x) => { |
| if (alreadyCalled === true) return; |
| alreadyCalled = true; |
| values[index] = x; |
| if (--count === 0) { |
| var valuesArray = []; |
| %MoveArrayContents(values, valuesArray); |
| %_Call(promiseCapability.resolve, UNDEFINED, valuesArray); |
| } |
| }; |
| } |
| |
| try { |
| var i = 0; |
| count = 1; |
| for (var value of iterable) { |
| var nextPromise = this.resolve(value); |
| ++count; |
| var throwawayPromise = nextPromise.then( |
| CreateResolveElementFunction(i, resolutions, deferred), |
| deferred.reject); |
| // For catch prediction, mark that rejections here are semantically |
| // handled by the combined Promise. |
| if (instrumenting && %is_promise(throwawayPromise)) { |
| SET_PRIVATE(throwawayPromise, promiseHandledBySymbol, deferred.promise); |
| } |
| ++i; |
| } |
| |
| // 6.d |
| if (--count === 0) { |
| var valuesArray = []; |
| %MoveArrayContents(resolutions, valuesArray); |
| %_Call(deferred.resolve, UNDEFINED, valuesArray); |
| } |
| |
| } catch (e) { |
| %_Call(deferred.reject, UNDEFINED, e); |
| } |
| return deferred.promise; |
| } |
| |
| // ES#sec-promise.race |
| // Promise.race ( iterable ) |
| function PromiseRace(iterable) { |
| if (!IS_RECEIVER(this)) { |
| throw %make_type_error(kCalledOnNonObject, PromiseRace); |
| } |
| |
| // false debugEvent so that forwarding the rejection through race does not |
| // trigger redundant ExceptionEvents |
| var deferred = %new_promise_capability(this, false); |
| |
| // For catch prediction, don't treat the .then calls as handling it; |
| // instead, recurse outwards. |
| var instrumenting = DEBUG_IS_ACTIVE; |
| if (instrumenting) { |
| SET_PRIVATE(deferred.reject, promiseForwardingHandlerSymbol, true); |
| } |
| |
| try { |
| for (var value of iterable) { |
| var throwawayPromise = this.resolve(value).then(deferred.resolve, |
| deferred.reject); |
| // For catch prediction, mark that rejections here are semantically |
| // handled by the combined Promise. |
| if (instrumenting && %is_promise(throwawayPromise)) { |
| SET_PRIVATE(throwawayPromise, promiseHandledBySymbol, deferred.promise); |
| } |
| } |
| } catch (e) { |
| %_Call(deferred.reject, UNDEFINED, e); |
| } |
| return deferred.promise; |
| } |
| |
| // ------------------------------------------------------------------- |
| // Install exported functions. |
| |
| utils.InstallFunctions(GlobalPromise, DONT_ENUM, [ |
| "all", PromiseAll, |
| "race", PromiseRace, |
| ]); |
| |
| }) |