Skip to content

Commit

Permalink
Implement Promise.try()
Browse files Browse the repository at this point in the history
  • Loading branch information
linusg committed Apr 9, 2024
1 parent 848103a commit eabe25b
Showing 1 changed file with 53 additions and 1 deletion.
54 changes: 53 additions & 1 deletion core/engine/src/builtins/promise/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down Expand Up @@ -462,6 +463,57 @@ 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<JsValue> {
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);

// 5. If status is an abrupt completion, then
if let Err(e) = status {
let value = e.to_opaque(context);

// a. Perform ? Call(promiseCapability.[[Reject]], undefined, « status.[[Value]] »).
promise_capability
.functions
.reject
.call(&JsValue::undefined(), &[value], context)?;
}
// 6. Else,
else {
let value = status.unwrap();

// 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
Expand All @@ -477,7 +529,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).
Expand Down

0 comments on commit eabe25b

Please sign in to comment.