internal static JsValue PerformPromiseThen( Engine engine, PromiseInstance promise, JsValue onFulfilled, JsValue onRejected, PromiseCapability resultCapability) { var fulfilReaction = new PromiseReaction(ReactionType.Fulfill, resultCapability, onFulfilled); var rejectReaction = new PromiseReaction(ReactionType.Reject, resultCapability, onRejected); switch (promise.State) { case PromiseState.Pending: promise.PromiseFulfillReactions.Add(fulfilReaction); promise.PromiseRejectReactions.Add(rejectReaction); break; case PromiseState.Fulfilled: engine.AddToEventLoop(NewPromiseReactionJob(fulfilReaction, promise.Value)); break; case PromiseState.Rejected: engine.AddToEventLoop(NewPromiseReactionJob(rejectReaction, promise.Value)); break; default: ExceptionHelper.ThrowArgumentOutOfRangeException(); break; } //https://tc39.es/ecma262/#sec-performpromisethen //... //13. If resultCapability is undefined, then // a. Return undefined //14. Else // a. Return resultCapability.[[Promise]] if (resultCapability is null) { return(JsValue.Undefined); } return(resultCapability.PromiseInstance); }
private static Action NewPromiseReactionJob(PromiseReaction reaction, JsValue value) { return(() => { var promiseCapability = reaction.Capability; if (reaction.Handler is ICallable handler) { try { var result = handler.Call(JsValue.Undefined, new[] { value }); promiseCapability.Resolve.Call(JsValue.Undefined, new[] { result }); } catch (JavaScriptException e) { promiseCapability.Reject.Call(JsValue.Undefined, new[] { e.Error }); } } else { switch (reaction.Type) { case ReactionType.Fulfill: promiseCapability.Resolve.Call(JsValue.Undefined, new[] { value }); break; case ReactionType.Reject: promiseCapability.Reject.Call(JsValue.Undefined, new[] { value }); break; default: throw new ArgumentOutOfRangeException(); } } }); }