Skip to content

Commit 1a5ee30

Browse files
littledivysaghul
authored andcommitted
Add JS_PromiseMarkAsHandled
Expose the existing internal js_promise_set_handled as a public API. Embedders that consume a rejected promise through the C API (rather than through a then() handler) currently have no way to tell the engine the rejection was handled, so the host promise rejection tracker reports it as unhandled. V8 exposes the same operation as v8::Promise::MarkAsHandled. Marking a rejected promise notifies the tracker once with is_handled true; marking a pending promise suppresses the report if it rejects later.
1 parent 8ef0e71 commit 1a5ee30

3 files changed

Lines changed: 50 additions & 0 deletions

File tree

api-test.c

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,49 @@ static void module_unhandled_rejection(void)
430430
JS_FreeRuntime(rt);
431431
}
432432

433+
static void promise_mark_as_handled(void)
434+
{
435+
struct rejection_counts c = {0, 0};
436+
JSRuntime *rt = new_runtime();
437+
JS_SetHostPromiseRejectionTracker(rt, rejection_counter, &c);
438+
JSContext *ctx = JS_NewContext(rt);
439+
JSContext *c1;
440+
441+
// marking an already-rejected promise notifies the tracker exactly once
442+
static const char code[] = "Promise.reject('kaboom')";
443+
JSValue promise = JS_Eval(ctx, code, strlen(code), "<t>", JS_EVAL_TYPE_GLOBAL);
444+
assert(JS_IsPromise(promise));
445+
while (JS_ExecutePendingJob(rt, &c1) > 0)
446+
;
447+
assert(c.reject_count == 1);
448+
assert(c.handle_count == 0);
449+
JS_PromiseMarkAsHandled(ctx, promise);
450+
assert(c.handle_count == 1);
451+
JS_PromiseMarkAsHandled(ctx, promise);
452+
assert(c.handle_count == 1);
453+
JS_FreeValue(ctx, promise);
454+
455+
// marking a pending promise suppresses the report when it later rejects
456+
JSValue resolving_funcs[2];
457+
JSValue promise2 = JS_NewPromiseCapability(ctx, resolving_funcs);
458+
JS_PromiseMarkAsHandled(ctx, promise2);
459+
JSValue reason = JS_NewString(ctx, "unseen");
460+
JSValue ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, 1,
461+
(JSValueConst *)&reason);
462+
while (JS_ExecutePendingJob(rt, &c1) > 0)
463+
;
464+
assert(c.reject_count == 1);
465+
assert(c.handle_count == 1);
466+
JS_FreeValue(ctx, ret);
467+
JS_FreeValue(ctx, reason);
468+
JS_FreeValue(ctx, resolving_funcs[0]);
469+
JS_FreeValue(ctx, resolving_funcs[1]);
470+
JS_FreeValue(ctx, promise2);
471+
472+
JS_FreeContext(ctx);
473+
JS_FreeRuntime(rt);
474+
}
475+
433476
static void runtime_cstring_free(void)
434477
{
435478
JSRuntime *rt = new_runtime();
@@ -1250,6 +1293,7 @@ int main(void)
12501293
is_array();
12511294
module_serde();
12521295
module_unhandled_rejection();
1296+
promise_mark_as_handled();
12531297
runtime_cstring_free();
12541298
utf16_string();
12551299
weak_map_gc_check();

quickjs.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55081,6 +55081,11 @@ bool JS_IsPromise(JSValueConst val)
5508155081
return JS_VALUE_GET_OBJ(val)->class_id == JS_CLASS_PROMISE;
5508255082
}
5508355083

55084+
void JS_PromiseMarkAsHandled(JSContext *ctx, JSValueConst promise)
55085+
{
55086+
js_promise_set_handled(ctx, promise);
55087+
}
55088+
5508455089
JSValue JS_NewSettledPromise(JSContext *ctx, bool is_reject, JSValueConst value)
5508555090
{
5508655091
return js_promise_resolve(ctx, ctx->promise_ctor, 1, &value, is_reject);

quickjs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1132,6 +1132,7 @@ JS_EXTERN JSPromiseStateEnum JS_PromiseState(JSContext *ctx,
11321132
JSValueConst promise);
11331133
JS_EXTERN JSValue JS_PromiseResult(JSContext *ctx, JSValueConst promise);
11341134
JS_EXTERN bool JS_IsPromise(JSValueConst val);
1135+
JS_EXTERN void JS_PromiseMarkAsHandled(JSContext *ctx, JSValueConst promise);
11351136
JS_EXTERN JSValue JS_NewSettledPromise(JSContext *ctx, bool is_reject, JSValueConst value);
11361137

11371138
JS_EXTERN JSValue JS_NewSymbol(JSContext *ctx, const char *description, bool is_global);

0 commit comments

Comments
 (0)