Introduce new Promise API methods (#3186)
The new API methods make it possible to get a Promise object's result and it's state. JerryScript-DCO-1.0-Signed-off-by: Peter Gal pgal.u-szeged@partner.samsung.com
This commit is contained in:
@@ -595,6 +595,22 @@ typedef jerry_value_t (*jerry_vm_exec_stop_callback_t) (void *user_p);
|
||||
|
||||
- [jerry_set_vm_exec_stop_callback](#jerry_set_vm_exec_stop_callback)
|
||||
|
||||
## jerry_promise_state_t
|
||||
|
||||
Enum which describes the state of a Promise.
|
||||
|
||||
Possible values:
|
||||
|
||||
- JERRY_PROMISE_STATE_NONE - Invalid/Unknown state (possibly called on a non-promise object).
|
||||
- JERRY_PROMISE_STATE_PENDING - Promise is in "Pending" state.
|
||||
- JERRY_PROMISE_STATE_FULFILLED - Promise is in "Fulfilled" state.
|
||||
- JERRY_PROMISE_STATE_REJECTED - Promise is in "Rejected" state.
|
||||
|
||||
*New in version [NEXT VERSION]*.
|
||||
|
||||
**See also**
|
||||
|
||||
- [jerry_get_promise_result](#jerry_get_promise_result)
|
||||
|
||||
## jerry_typedarray_type_t
|
||||
|
||||
@@ -3231,6 +3247,144 @@ jerry_value_to_string (const jerry_value_t value);
|
||||
|
||||
These APIs all depend on the ES2015-subset profile (or on some build options).
|
||||
|
||||
## jerry_get_promise_result
|
||||
|
||||
**Summary**
|
||||
|
||||
The function returns the result of a Promise object.
|
||||
|
||||
*Notes*:
|
||||
- Returned value must be freed with [jerry_release_value](#jerry_release_value) when it
|
||||
is no longer needed.
|
||||
- This API depends on a build option (`JERRY_ES2015_BUILTIN_PROMISE`) and can be checked
|
||||
in runtime with the `JERRY_FEATURE_PROMISE` feature enum value,
|
||||
see: [jerry_is_feature_enabled](#jerry_is_feature_enabled).
|
||||
- The ES2015-subset profile enables this by default.
|
||||
|
||||
|
||||
**Prototype**
|
||||
|
||||
```c
|
||||
jerry_value_t
|
||||
jerry_get_promise_result (const jerry_value_t promise);
|
||||
```
|
||||
|
||||
- `promise` - the input Promise object.
|
||||
- return
|
||||
- The result of the Promise.
|
||||
- If the Promise is not resolved yet the result is the 'undefined' value.
|
||||
- A TypeError is returned if the input argument was not a Promise object or
|
||||
the Promise support was not built into the library.
|
||||
|
||||
*New in version [NEXT VERSION]*.
|
||||
|
||||
**Example**
|
||||
|
||||
[doctest]: # (test="compile")
|
||||
|
||||
```c
|
||||
#include <jerryscript.h>
|
||||
|
||||
static void
|
||||
example (void)
|
||||
{
|
||||
// acquire/create a promise object.
|
||||
jerry_value_t promise = jerry_create_promise ();
|
||||
{
|
||||
// prepare the argumnent for the resolve or reject.
|
||||
jerry_value_t argument = jerry_create_number (33);
|
||||
|
||||
jerry_value_t is_ok = jerry_resolve_or_reject_promise (promise,
|
||||
argument,
|
||||
true);
|
||||
// 'is_ok' should be checked if it is an error or not.
|
||||
// skipped in this example
|
||||
jerry_release_value (is_ok);
|
||||
jerry_release_value (argument);
|
||||
}
|
||||
|
||||
jerry_value_t promise_result = jerry_get_promise_result (promise);
|
||||
// 'promise_result' is now the number 33.
|
||||
|
||||
jerry_release_value (promise_result);
|
||||
jerry_release_value (promise);
|
||||
}
|
||||
```
|
||||
|
||||
**See also**
|
||||
|
||||
- [jerry_create_promise](#jerry_create_promise)
|
||||
- [jerry_promise_state_t](#jerry_promise_state_t)
|
||||
|
||||
## jerry_get_promise_state
|
||||
|
||||
**Summary**
|
||||
|
||||
*Notes*:
|
||||
- Returned value must be freed with [jerry_release_value](#jerry_release_value) when it
|
||||
is no longer needed.
|
||||
- This API depends on a build option (`JERRY_ES2015_BUILTIN_PROMISE`) and can be checked
|
||||
in runtime with the `JERRY_FEATURE_PROMISE` feature enum value,
|
||||
see: [jerry_is_feature_enabled](#jerry_is_feature_enabled).
|
||||
- The ES2015-subset profile enables this by default.
|
||||
|
||||
|
||||
**Prototype**
|
||||
|
||||
```c
|
||||
jerry_promise_state_t
|
||||
jerry_get_promise_state (const jerry_value_t promise);
|
||||
```
|
||||
|
||||
- `promise` - the input promise object.
|
||||
- return
|
||||
- [jerry_promise_state_t](#jerry_promise_state_t)
|
||||
- `JERRY_PROMISE_STATE_NONE` is returned if the input argument was not a promise object or
|
||||
the Promise support was not built into the library.
|
||||
|
||||
*New in version [NEXT VERSION]*.
|
||||
|
||||
**Example**
|
||||
|
||||
[doctest]: # (test="compile")
|
||||
|
||||
```c
|
||||
#include <jerryscript.h>
|
||||
|
||||
static void
|
||||
example (void)
|
||||
{
|
||||
// acquire/create a promise object.
|
||||
jerry_value_t promise = jerry_create_promise ();
|
||||
|
||||
jerry_promise_state_t start_state = jerry_get_promise_state (promise);
|
||||
// a Promise have a default state of JERRY_PROMISE_STATE_PENDING
|
||||
|
||||
{
|
||||
// prepare the argumnent for the resolve or reject.
|
||||
jerry_value_t argument = jerry_create_number (33);
|
||||
|
||||
jerry_value_t is_ok = jerry_resolve_or_reject_promise (promise,
|
||||
argument,
|
||||
true);
|
||||
// 'is_ok' should be checked if it is an error or not.
|
||||
// skipped in this example
|
||||
jerry_release_value (is_ok);
|
||||
jerry_release_value (argument);
|
||||
}
|
||||
|
||||
jerry_promise_state_t current_state = jerry_get_promise_state (promise);
|
||||
// at this point the Promise should be in the JERRY_PROMISE_STATE_FULFILLED state.
|
||||
|
||||
jerry_release_value (promise);
|
||||
}
|
||||
```
|
||||
|
||||
**See also**
|
||||
|
||||
- [jerry_create_promise](#jerry_create_promise)
|
||||
- [jerry_promise_state_t](#jerry_promise_state_t)
|
||||
|
||||
## jerry_resolve_or_reject_promise
|
||||
|
||||
**Summary**
|
||||
|
||||
@@ -71,6 +71,14 @@ JERRY_STATIC_ASSERT ((int) RE_FLAG_GLOBAL == (int) JERRY_REGEXP_FLAG_GLOBAL
|
||||
re_flags_t_must_be_equal_to_jerry_regexp_flags_t);
|
||||
#endif /* ENABLED (JERRY_BUILTIN_REGEXP) */
|
||||
|
||||
#if ENABLED (JERRY_ES2015_BUILTIN_PROMISE)
|
||||
/* The internal ECMA_PROMISE_STATE_* values are "one byte away" from the API values */
|
||||
JERRY_STATIC_ASSERT (((ECMA_PROMISE_STATE_PENDING + 1) == JERRY_PROMISE_STATE_PENDING)
|
||||
&& ((ECMA_PROMISE_STATE_FULFILLED + 1) == JERRY_PROMISE_STATE_FULFILLED)
|
||||
&& ((ECMA_PROMISE_STATE_REJECTED + 1) == JERRY_PROMISE_STATE_REJECTED),
|
||||
promise_internal_state_matches_external);
|
||||
#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */
|
||||
|
||||
#if !ENABLED (JERRY_PARSER) && !ENABLED (JERRY_SNAPSHOT_EXEC)
|
||||
#error "JERRY_SNAPSHOT_EXEC must be enabled if JERRY_PARSER is disabled!"
|
||||
#endif /* !ENABLED (JERRY_PARSER) && !ENABLED (JERRY_SNAPSHOT_EXEC) */
|
||||
@@ -3084,6 +3092,60 @@ jerry_resolve_or_reject_promise (jerry_value_t promise, /**< the promise value *
|
||||
#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */
|
||||
} /* jerry_resolve_or_reject_promise */
|
||||
|
||||
/**
|
||||
* Get the result of a promise.
|
||||
*
|
||||
* @return - Promise result
|
||||
* - Type error if the promise support was not enabled or the input was not a promise object
|
||||
*/
|
||||
jerry_value_t
|
||||
jerry_get_promise_result (const jerry_value_t promise) /**< promise object to get the result from */
|
||||
{
|
||||
jerry_assert_api_available ();
|
||||
|
||||
#if ENABLED (JERRY_ES2015_BUILTIN_PROMISE)
|
||||
if (!jerry_value_is_promise (promise))
|
||||
{
|
||||
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (wrong_args_msg_p)));
|
||||
}
|
||||
|
||||
return ecma_promise_get_result (ecma_get_object_from_value (promise));
|
||||
#else /* !ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */
|
||||
JERRY_UNUSED (promise);
|
||||
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG ("Promise not supported.")));
|
||||
#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */
|
||||
} /* jerry_get_promise_result */
|
||||
|
||||
/**
|
||||
* Get the state of a promise object.
|
||||
*
|
||||
* @return - the state of the promise (one of the jerry_promise_state_t enum values)
|
||||
* - JERRY_PROMISE_STATE_NONE is only returned if the input is not a promise object
|
||||
* or the promise support was not enabled.
|
||||
*/
|
||||
jerry_promise_state_t
|
||||
jerry_get_promise_state (const jerry_value_t promise) /**< promise object to get the state from */
|
||||
{
|
||||
jerry_assert_api_available ();
|
||||
|
||||
#if ENABLED (JERRY_ES2015_BUILTIN_PROMISE)
|
||||
if (!jerry_value_is_promise (promise))
|
||||
{
|
||||
return JERRY_PROMISE_STATE_NONE;
|
||||
}
|
||||
|
||||
uint8_t state = ecma_promise_get_state (ecma_get_object_from_value (promise));
|
||||
|
||||
JERRY_ASSERT (state < ECMA_PROMISE_STATE__COUNT);
|
||||
|
||||
/* Static assert above guarantees the mapping from internal type to external type. */
|
||||
return (jerry_promise_state_t) (state + 1);
|
||||
#else /* !ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */
|
||||
JERRY_UNUSED (promise);
|
||||
return JERRY_PROMISE_STATE_NONE;
|
||||
#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */
|
||||
} /* jerry_get_promise_state */
|
||||
|
||||
/**
|
||||
* Call the SymbolDescriptiveString ecma builtin operation on the symbol value.
|
||||
*
|
||||
|
||||
@@ -53,7 +53,7 @@ ecma_is_promise (ecma_object_t *obj_p) /**< points to object */
|
||||
* @return ecma value of the promise result.
|
||||
* Returned value must be freed with ecma_free_value
|
||||
*/
|
||||
static inline ecma_value_t
|
||||
ecma_value_t
|
||||
ecma_promise_get_result (ecma_object_t *obj_p) /**< points to promise object */
|
||||
{
|
||||
JERRY_ASSERT (ecma_is_promise (obj_p));
|
||||
@@ -84,7 +84,7 @@ ecma_promise_set_result (ecma_object_t *obj_p, /**< points to promise object */
|
||||
*
|
||||
* @return the state's enum value
|
||||
*/
|
||||
static inline uint8_t JERRY_ATTR_ALWAYS_INLINE
|
||||
uint8_t
|
||||
ecma_promise_get_state (ecma_object_t *obj_p) /**< points to promise object */
|
||||
{
|
||||
JERRY_ASSERT (ecma_is_promise (obj_p));
|
||||
|
||||
@@ -71,6 +71,8 @@ typedef struct
|
||||
bool ecma_is_promise (ecma_object_t *obj_p);
|
||||
ecma_value_t
|
||||
ecma_op_create_promise_object (ecma_value_t executor, ecma_promise_executor_type_t type);
|
||||
uint8_t ecma_promise_get_state (ecma_object_t *promise_p);
|
||||
ecma_value_t ecma_promise_get_result (ecma_object_t *promise_p);
|
||||
ecma_value_t ecma_promise_new_capability (void);
|
||||
ecma_value_t
|
||||
ecma_promise_then (ecma_value_t promise,
|
||||
|
||||
@@ -555,10 +555,24 @@ bool jerry_foreach_object_property (const jerry_value_t obj_val, jerry_object_pr
|
||||
void *user_data_p);
|
||||
|
||||
/**
|
||||
* Promise resolve/reject functions.
|
||||
* Promise functions.
|
||||
*/
|
||||
jerry_value_t jerry_resolve_or_reject_promise (jerry_value_t promise, jerry_value_t argument, bool is_resolve);
|
||||
|
||||
/**
|
||||
* Enum values representing various Promise states.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
JERRY_PROMISE_STATE_NONE = 0u, /**< Invalid/Unknown state (possibly called on a non-promise object). */
|
||||
JERRY_PROMISE_STATE_PENDING, /**< Promise is in "Pending" state. */
|
||||
JERRY_PROMISE_STATE_FULFILLED, /**< Promise is in "Fulfilled" state. */
|
||||
JERRY_PROMISE_STATE_REJECTED, /**< Promise is in "Rejected" state. */
|
||||
} jerry_promise_state_t;
|
||||
|
||||
jerry_value_t jerry_get_promise_result (const jerry_value_t promise);
|
||||
jerry_promise_state_t jerry_get_promise_state (const jerry_value_t promise);
|
||||
|
||||
/**
|
||||
* Symbol functions.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,205 @@
|
||||
/* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "jerryscript.h"
|
||||
#include "jerryscript-port.h"
|
||||
#include "jerryscript-port-default.h"
|
||||
#include "test-common.h"
|
||||
|
||||
static void
|
||||
test_promise_resolve_success (void)
|
||||
{
|
||||
jerry_value_t my_promise = jerry_create_promise ();
|
||||
|
||||
// A created promise has an undefined promise result by default and a pending state
|
||||
{
|
||||
jerry_value_t promise_result = jerry_get_promise_result (my_promise);
|
||||
TEST_ASSERT (jerry_value_is_undefined (promise_result));
|
||||
|
||||
jerry_promise_state_t promise_state = jerry_get_promise_state (my_promise);
|
||||
TEST_ASSERT (promise_state == JERRY_PROMISE_STATE_PENDING);
|
||||
|
||||
jerry_release_value (promise_result);
|
||||
}
|
||||
|
||||
jerry_value_t resolve_value = jerry_create_object ();
|
||||
{
|
||||
jerry_value_t obj_key = jerry_create_string ((const jerry_char_t *) "key_one");
|
||||
jerry_value_t set_result = jerry_set_property (resolve_value, obj_key, jerry_create_number (3));
|
||||
TEST_ASSERT (jerry_value_is_boolean (set_result) && (jerry_get_boolean_value (set_result) == true));
|
||||
jerry_release_value (set_result);
|
||||
jerry_release_value (obj_key);
|
||||
}
|
||||
|
||||
// A resolved promise should have the result of from the resolve call and a fulfilled state
|
||||
{
|
||||
jerry_value_t resolve_result = jerry_resolve_or_reject_promise (my_promise, resolve_value, true);
|
||||
|
||||
// Release "old" value of resolve.
|
||||
jerry_release_value (resolve_value);
|
||||
|
||||
jerry_value_t promise_result = jerry_get_promise_result (my_promise);
|
||||
{
|
||||
TEST_ASSERT (jerry_value_is_object (promise_result));
|
||||
jerry_value_t obj_key = jerry_create_string ((const jerry_char_t *) "key_one");
|
||||
jerry_value_t get_result = jerry_get_property (promise_result, obj_key);
|
||||
TEST_ASSERT (jerry_value_is_number (get_result));
|
||||
TEST_ASSERT (jerry_get_number_value (get_result) == 3.0);
|
||||
|
||||
jerry_release_value (get_result);
|
||||
jerry_release_value (obj_key);
|
||||
}
|
||||
|
||||
jerry_promise_state_t promise_state = jerry_get_promise_state (my_promise);
|
||||
TEST_ASSERT (promise_state == JERRY_PROMISE_STATE_FULFILLED);
|
||||
|
||||
jerry_release_value (promise_result);
|
||||
|
||||
jerry_release_value (resolve_result);
|
||||
}
|
||||
|
||||
// Resolvind a promise again does not change the result/state
|
||||
{
|
||||
jerry_value_t resolve_result = jerry_resolve_or_reject_promise (my_promise, jerry_create_number (50), false);
|
||||
|
||||
jerry_value_t promise_result = jerry_get_promise_result (my_promise);
|
||||
{
|
||||
TEST_ASSERT (jerry_value_is_object (promise_result));
|
||||
jerry_value_t obj_key = jerry_create_string ((const jerry_char_t *) "key_one");
|
||||
jerry_value_t get_result = jerry_get_property (promise_result, obj_key);
|
||||
TEST_ASSERT (jerry_value_is_number (get_result));
|
||||
TEST_ASSERT (jerry_get_number_value (get_result) == 3.0);
|
||||
|
||||
jerry_release_value (get_result);
|
||||
jerry_release_value (obj_key);
|
||||
}
|
||||
|
||||
jerry_promise_state_t promise_state = jerry_get_promise_state (my_promise);
|
||||
TEST_ASSERT (promise_state == JERRY_PROMISE_STATE_FULFILLED);
|
||||
|
||||
jerry_release_value (promise_result);
|
||||
|
||||
jerry_release_value (resolve_result);
|
||||
}
|
||||
|
||||
jerry_release_value (my_promise);
|
||||
} /* test_promise_resolve_success */
|
||||
|
||||
static void
|
||||
test_promise_resolve_fail (void)
|
||||
{
|
||||
jerry_value_t my_promise = jerry_create_promise ();
|
||||
|
||||
// A created promise has an undefined promise result by default and a pending state
|
||||
{
|
||||
jerry_value_t promise_result = jerry_get_promise_result (my_promise);
|
||||
TEST_ASSERT (jerry_value_is_undefined (promise_result));
|
||||
|
||||
jerry_promise_state_t promise_state = jerry_get_promise_state (my_promise);
|
||||
TEST_ASSERT (promise_state == JERRY_PROMISE_STATE_PENDING);
|
||||
|
||||
jerry_release_value (promise_result);
|
||||
}
|
||||
|
||||
// A resolved promise should have the result of from the resolve call and a fulfilled state
|
||||
{
|
||||
jerry_value_t error_value = jerry_create_error (JERRY_ERROR_TYPE, (const jerry_char_t *) "resolve_fail");
|
||||
jerry_value_t error_obj = jerry_get_value_from_error (error_value, true);
|
||||
jerry_value_t resolve_result = jerry_resolve_or_reject_promise (my_promise, error_obj, false);
|
||||
jerry_release_value (error_obj);
|
||||
|
||||
jerry_value_t promise_result = jerry_get_promise_result (my_promise);
|
||||
// The error is not throw that's why it is only an error object.
|
||||
TEST_ASSERT (jerry_value_is_object (promise_result));
|
||||
TEST_ASSERT (jerry_get_error_type (promise_result) == JERRY_ERROR_TYPE);
|
||||
|
||||
jerry_promise_state_t promise_state = jerry_get_promise_state (my_promise);
|
||||
TEST_ASSERT (promise_state == JERRY_PROMISE_STATE_REJECTED);
|
||||
|
||||
jerry_release_value (promise_result);
|
||||
|
||||
jerry_release_value (resolve_result);
|
||||
}
|
||||
|
||||
// Resolvind a promise again does not change the result/state
|
||||
{
|
||||
jerry_value_t resolve_result = jerry_resolve_or_reject_promise (my_promise, jerry_create_number (50), true);
|
||||
|
||||
jerry_value_t promise_result = jerry_get_promise_result (my_promise);
|
||||
TEST_ASSERT (jerry_value_is_object (promise_result));
|
||||
TEST_ASSERT (jerry_get_error_type (promise_result) == JERRY_ERROR_TYPE);
|
||||
|
||||
jerry_promise_state_t promise_state = jerry_get_promise_state (my_promise);
|
||||
TEST_ASSERT (promise_state == JERRY_PROMISE_STATE_REJECTED);
|
||||
|
||||
jerry_release_value (promise_result);
|
||||
|
||||
jerry_release_value (resolve_result);
|
||||
}
|
||||
|
||||
jerry_release_value (my_promise);
|
||||
} /* test_promise_resolve_fail */
|
||||
|
||||
static void
|
||||
test_promise_from_js (void)
|
||||
{
|
||||
const jerry_char_t test_source[] = "(new Promise(function(rs, rj) { rs(30); })).then(function(v) { return v + 1; })";
|
||||
|
||||
jerry_value_t parsed_code_val = jerry_parse (NULL,
|
||||
0,
|
||||
test_source,
|
||||
sizeof (test_source) - 1,
|
||||
JERRY_PARSE_NO_OPTS);
|
||||
TEST_ASSERT (!jerry_value_is_error (parsed_code_val));
|
||||
|
||||
jerry_value_t res = jerry_run (parsed_code_val);
|
||||
TEST_ASSERT (jerry_value_is_promise (res));
|
||||
|
||||
TEST_ASSERT (jerry_get_promise_state (res) == JERRY_PROMISE_STATE_PENDING);
|
||||
|
||||
jerry_value_t run_result = jerry_run_all_enqueued_jobs ();
|
||||
TEST_ASSERT (jerry_value_is_undefined (run_result));
|
||||
jerry_release_value (run_result);
|
||||
|
||||
TEST_ASSERT (jerry_get_promise_state (res) == JERRY_PROMISE_STATE_FULFILLED);
|
||||
jerry_value_t promise_result = jerry_get_promise_result (res);
|
||||
TEST_ASSERT (jerry_value_is_number (promise_result));
|
||||
TEST_ASSERT (jerry_get_number_value (promise_result) == 31.0);
|
||||
|
||||
jerry_release_value (promise_result);
|
||||
jerry_release_value (res);
|
||||
jerry_release_value (parsed_code_val);
|
||||
} /* test_promise_from_js */
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
if (!jerry_is_feature_enabled (JERRY_FEATURE_PROMISE))
|
||||
{
|
||||
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Promise is disabled!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
jerry_init (JERRY_INIT_EMPTY);
|
||||
|
||||
test_promise_resolve_fail ();
|
||||
test_promise_resolve_success ();
|
||||
|
||||
test_promise_from_js ();
|
||||
|
||||
jerry_cleanup ();
|
||||
|
||||
return 0;
|
||||
} /* main */
|
||||
Reference in New Issue
Block a user