diff --git a/core/engine/src/builtins/promise/mod.rs b/core/engine/src/builtins/promise/mod.rs index ba5395d0068..c48ed69dec5 100644 --- a/core/engine/src/builtins/promise/mod.rs +++ b/core/engine/src/builtins/promise/mod.rs @@ -347,6 +347,7 @@ impl IntrinsicObject for Promise { .static_method(Self::race, js_string!("race"), 1) .static_method(Self::reject, js_string!("reject"), 1) .static_method(Self::resolve, js_string!("resolve"), 1) + .static_method(Self::r#try, js_string!("try"), 1) .static_method(Self::with_resolvers, js_string!("withResolvers"), 0) .static_accessor( JsSymbol::species(), @@ -462,6 +463,59 @@ impl Promise { &self.state } + /// [`Promise.try ( callbackfn, ...args )`][spec] + /// + /// Calls the given function and returns a new promise that is resolved if the function + /// completes normally and rejected if it throws. + /// + /// [spec]: https://tc39.es/proposal-promise-try/#sec-promise.try + pub(crate) fn r#try( + this: &JsValue, + args: &[JsValue], + context: &mut Context, + ) -> JsResult { + let callback = args.get_or_undefined(0); + let callback_args = args.get(1..).unwrap_or(&[]); + + // 1. Let C be the this value. + // 2. If C is not an Object, throw a TypeError exception. + let c = this.as_object().ok_or_else(|| { + JsNativeError::typ().with_message("Promise.try() called on a non-object") + })?; + + // 3. Let promiseCapability be ? NewPromiseCapability(C). + let promise_capability = PromiseCapability::new(c, context)?; + + // 4. Let status be Completion(Call(callbackfn, undefined, args)). + let status = callback.call(&JsValue::undefined(), callback_args, context); + + match status { + // 5. If status is an abrupt completion, then + Err(err) => { + let value = err.to_opaque(context); + + // a. Perform ? Call(promiseCapability.[[Reject]], undefined, « status.[[Value]] »). + promise_capability.functions.reject.call( + &JsValue::undefined(), + &[value], + context, + )?; + } + // 6. Else, + Ok(value) => { + // a. Perform ? Call(promiseCapability.[[Resolve]], undefined, « status.[[Value]] »). + promise_capability.functions.resolve.call( + &JsValue::undefined(), + &[value], + context, + )?; + } + } + + // 7. Return promiseCapability.[[Promise]]. + Ok(promise_capability.promise.clone().into()) + } + /// [`Promise.withResolvers ( )`][spec] /// /// Creates a new promise that is pending, and returns that promise plus the resolve and reject @@ -477,7 +531,7 @@ impl Promise { use super::OrdinaryObject; let c = this.as_object().ok_or_else(|| { - JsNativeError::typ().with_message("Promise.all() called on a non-object") + JsNativeError::typ().with_message("Promise.withResolvers() called on a non-object") })?; // 2. Let promiseCapability be ? NewPromiseCapability(C).