|  | /* | 
|  | * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>. | 
|  | * Copyright (C) 2016 Apple Inc. All rights reserved. | 
|  | * | 
|  | * Redistribution and use in source and binary forms, with or without | 
|  | * modification, are permitted provided that the following conditions | 
|  | * are met: | 
|  | * 1. Redistributions of source code must retain the above copyright | 
|  | *    notice, this list of conditions and the following disclaimer. | 
|  | * 2. Redistributions in binary form must reproduce the above copyright | 
|  | *    notice, this list of conditions and the following disclaimer in the | 
|  | *    documentation and/or other materials provided with the distribution. | 
|  | * | 
|  | * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY | 
|  | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 
|  | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 
|  | * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR | 
|  | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | 
|  | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | 
|  | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | 
|  | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | 
|  | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
|  | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
|  | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
|  | */ | 
|  |  | 
|  | // @internal | 
|  |  | 
|  | @globalPrivate | 
|  | function isPromise(promise) | 
|  | { | 
|  | "use strict"; | 
|  |  | 
|  | return @isObject(promise) && !!@getByIdDirectPrivate(promise, "promiseState"); | 
|  | } | 
|  |  | 
|  | @globalPrivate | 
|  | function newPromiseReaction(capability, onFulfilled, onRejected) | 
|  | { | 
|  | "use strict"; | 
|  |  | 
|  | return { | 
|  | @capabilities: capability, | 
|  | @onFulfilled: onFulfilled, | 
|  | @onRejected: onRejected, | 
|  | }; | 
|  | } | 
|  |  | 
|  | @globalPrivate | 
|  | function newPromiseCapability(constructor) | 
|  | { | 
|  | "use strict"; | 
|  |  | 
|  | if (!@isConstructor(constructor)) | 
|  | @throwTypeError("promise capability requires a constructor function"); | 
|  |  | 
|  | var promiseCapability = { | 
|  | @promise: @undefined, | 
|  | @resolve: @undefined, | 
|  | @reject: @undefined | 
|  | }; | 
|  |  | 
|  | function @executor(resolve, reject) | 
|  | { | 
|  | if (promiseCapability.@resolve !== @undefined) | 
|  | @throwTypeError("resolve function is already set"); | 
|  | if (promiseCapability.@reject !== @undefined) | 
|  | @throwTypeError("reject function is already set"); | 
|  |  | 
|  | promiseCapability.@resolve = resolve; | 
|  | promiseCapability.@reject = reject; | 
|  | } | 
|  |  | 
|  | var promise = new constructor(@executor); | 
|  |  | 
|  | if (typeof promiseCapability.@resolve !== "function") | 
|  | @throwTypeError("executor did not take a resolve function"); | 
|  |  | 
|  | if (typeof promiseCapability.@reject !== "function") | 
|  | @throwTypeError("executor did not take a reject function"); | 
|  |  | 
|  | promiseCapability.@promise = promise; | 
|  |  | 
|  | return promiseCapability; | 
|  | } | 
|  |  | 
|  | @globalPrivate | 
|  | function newHandledRejectedPromise(error) | 
|  | { | 
|  | "use strict"; | 
|  | let promise = @Promise.@reject(error); | 
|  | @putByIdDirectPrivate(promise, "promiseIsHandled", true); | 
|  | return promise; | 
|  | } | 
|  |  | 
|  | @globalPrivate | 
|  | function triggerPromiseReactions(state, reactions, argument) | 
|  | { | 
|  | "use strict"; | 
|  |  | 
|  | for (var index = 0, length = reactions.length; index < length; ++index) | 
|  | @enqueueJob(@promiseReactionJob, [state, reactions[index], argument]); | 
|  | } | 
|  |  | 
|  | @globalPrivate | 
|  | function rejectPromise(promise, reason) | 
|  | { | 
|  | "use strict"; | 
|  |  | 
|  | var reactions = @getByIdDirectPrivate(promise, "promiseReactions"); | 
|  | @putByIdDirectPrivate(promise, "promiseResult", reason); | 
|  | @putByIdDirectPrivate(promise, "promiseReactions", @undefined); | 
|  | @putByIdDirectPrivate(promise, "promiseState", @promiseStateRejected); | 
|  |  | 
|  | @InspectorInstrumentation.promiseRejected(promise, reason, reactions); | 
|  |  | 
|  | if (!@getByIdDirectPrivate(promise, "promiseIsHandled")) | 
|  | @hostPromiseRejectionTracker(promise, @promiseRejectionReject); | 
|  |  | 
|  | @triggerPromiseReactions(@promiseStateRejected, reactions, reason); | 
|  | } | 
|  |  | 
|  | @globalPrivate | 
|  | function fulfillPromise(promise, value) | 
|  | { | 
|  | "use strict"; | 
|  |  | 
|  | var reactions = @getByIdDirectPrivate(promise, "promiseReactions"); | 
|  | @putByIdDirectPrivate(promise, "promiseResult", value); | 
|  | @putByIdDirectPrivate(promise, "promiseReactions", @undefined); | 
|  | @putByIdDirectPrivate(promise, "promiseState", @promiseStateFulfilled); | 
|  |  | 
|  | @InspectorInstrumentation.promiseFulfilled(promise, value, reactions); | 
|  |  | 
|  | @triggerPromiseReactions(@promiseStateFulfilled, reactions, value); | 
|  | } | 
|  |  | 
|  | @globalPrivate | 
|  | function createResolvingFunctions(promise) | 
|  | { | 
|  | "use strict"; | 
|  |  | 
|  | var alreadyResolved = false; | 
|  |  | 
|  | function @resolve(resolution) { | 
|  | if (alreadyResolved) | 
|  | return @undefined; | 
|  | alreadyResolved = true; | 
|  |  | 
|  | if (resolution === promise) | 
|  | return @rejectPromise(promise, new @TypeError("Resolve a promise with itself")); | 
|  |  | 
|  | if (!@isObject(resolution)) | 
|  | return @fulfillPromise(promise, resolution); | 
|  |  | 
|  | var then; | 
|  | try { | 
|  | then = resolution.then; | 
|  | } catch (error) { | 
|  | return @rejectPromise(promise, error); | 
|  | } | 
|  |  | 
|  | if (typeof then !== 'function') | 
|  | return @fulfillPromise(promise, resolution); | 
|  |  | 
|  | @enqueueJob(@promiseResolveThenableJob, [promise, resolution, then]); | 
|  |  | 
|  | return @undefined; | 
|  | } | 
|  |  | 
|  | function @reject(reason) { | 
|  | if (alreadyResolved) | 
|  | return @undefined; | 
|  | alreadyResolved = true; | 
|  |  | 
|  | return @rejectPromise(promise, reason); | 
|  | } | 
|  |  | 
|  | return { @resolve, @reject }; | 
|  | } | 
|  |  | 
|  | @globalPrivate | 
|  | function promiseReactionJob(state, reaction, argument) | 
|  | { | 
|  | "use strict"; | 
|  |  | 
|  | var promiseCapability = reaction.@capabilities; | 
|  |  | 
|  | var result; | 
|  | var handler = (state === @promiseStateFulfilled) ? reaction.@onFulfilled: reaction.@onRejected; | 
|  | try { | 
|  | result = handler(argument); | 
|  | } catch (error) { | 
|  | return promiseCapability.@reject.@call(@undefined, error); | 
|  | } | 
|  |  | 
|  | return promiseCapability.@resolve.@call(@undefined, result); | 
|  | } | 
|  |  | 
|  | @globalPrivate | 
|  | function promiseResolveThenableJob(promiseToResolve, thenable, then) | 
|  | { | 
|  | "use strict"; | 
|  |  | 
|  | var resolvingFunctions = @createResolvingFunctions(promiseToResolve); | 
|  |  | 
|  | try { | 
|  | return then.@call(thenable, resolvingFunctions.@resolve, resolvingFunctions.@reject); | 
|  | } catch (error) { | 
|  | return resolvingFunctions.@reject.@call(@undefined, error); | 
|  | } | 
|  | } | 
|  |  | 
|  | @globalPrivate | 
|  | function initializePromise(executor) | 
|  | { | 
|  | "use strict"; | 
|  |  | 
|  | if (typeof executor !== 'function') | 
|  | @throwTypeError("Promise constructor takes a function argument"); | 
|  |  | 
|  | @putByIdDirectPrivate(this, "promiseState", @promiseStatePending); | 
|  | @putByIdDirectPrivate(this, "promiseReactions", []); | 
|  | @putByIdDirectPrivate(this, "promiseIsHandled", false); | 
|  |  | 
|  | var resolvingFunctions = @createResolvingFunctions(this); | 
|  | try { | 
|  | executor(resolvingFunctions.@resolve, resolvingFunctions.@reject); | 
|  | } catch (error) { | 
|  | return resolvingFunctions.@reject.@call(@undefined, error); | 
|  | } | 
|  |  | 
|  | return this; | 
|  | } |