-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Handle promise reject handler added later issue #959
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great! I'm not sure about the API... but glad these tricky bugs are being nailed down.
@piscisaureus Please review.
libdeno/deno.h
Outdated
@@ -59,6 +59,8 @@ int deno_execute(Deno* d, void* user_data, const char* js_filename, | |||
// libdeno.recv() callback. Check deno_last_exception() for exception text. | |||
int deno_respond(Deno* d, void* user_data, int32_t req_id, deno_buf buf); | |||
|
|||
void deno_check_promise_reject_events(Deno* d); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add tests to libdeno/libdeno_test.cc
93a9ee1
to
88a22c0
Compare
} | ||
d->pending_promise_events = 0; // reset | ||
if (result->Uint32Value(context).FromJust() == 1) { | ||
exit(1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Checking returned value and exit here is not quite ideal... However, if I were to use os.exit(...)
from TS side in promiseErrorExaminer
it would trigger segfault.
Not quite sure what I did wrong
libdeno/binding.cc
Outdated
@@ -322,6 +396,43 @@ bool Execute(v8::Local<v8::Context> context, const char* js_filename, | |||
return ExecuteV8StringSource(context, js_filename, source); | |||
} | |||
|
|||
v8::Local<v8::Object> InitializeConstants(v8::Isolate* isolate, | |||
v8::Local<v8::Context> context) { | |||
auto constants_val = v8::Object::New(isolate); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Put these directly into the libdeno
namespace, not libdeno.constants
libdeno/binding.cc
Outdated
|
||
auto promise_reject_event_val = v8::Object::New(isolate); | ||
CHECK(promise_reject_event_val | ||
->Set(context, deno::v8_str("kPromiseRejectWithNoHandler"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
put this directly into the libdeno namespace, not libdeno.constants.promiseRejectEvents
assertOrSend(count === 2); | ||
} | ||
})(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice work!
js/libdeno.ts
Outdated
setPromiseRejectHandler: ( | ||
handler: ( | ||
error: Error, | ||
event: number, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about about
event: "RejectWithNoHandler" | "HandlerAddedAfterReject" | "ResolveAfterResolved" | "RejectAfterResolved"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Event types from v8 here are integers. Not quite sure if we want to covert to string reprs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only concern would be about performance.. presumably numbers are faster.
Is this hot code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The handler is invoked twice for each caught promise reject. Not quite sure if it is considered hot enough
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think mapping the V8 numbers to strings in C++ isn't so bad. This will simply the libdeno JS interface quite a bit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const char* PromiseRejectStr(enum v8::PromiseRejectEvent e) {
switch (e) {
case kPromiseRejectWithNoHandler:
return "RejectWithNoHandler";
case kPromiseHandlerAddedAfterReject:
return "HandlerAddedAfterReject";
case kPromiseResolveAfterResolved:
return "ResolveAfterResolved";
case kPromiseRejectAfterResolved:
return "RejectAfterResolved";
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! Added the function.
js/promise_util.ts
Outdated
const promiseRejectEvents = libdeno.constants.promiseRejectEvents; | ||
|
||
/* tslint:disable-next-line:no-any */ | ||
const promiseRejectMap = new Map<Promise<any>, string>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
:%s/promiseRejectMap/rejectMap/g
js/promise_util.ts
Outdated
/* tslint:disable-next-line:no-any */ | ||
const promiseRejectMap = new Map<Promise<any>, string>(); | ||
/* tslint:disable-next-line:no-any */ | ||
const otherPromiseErrorMap = new Map<Promise<any>, string>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
%s/otherPromiseErrorMap/otherErrorMap/g
js/promise_util.ts
Outdated
promiseRejectMap.clear(); | ||
return 1; | ||
} | ||
return 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
deno.exit() requires message passing - which probably doesn't work in this state of error.
maybe we should add libdeno.exit() as a way to quickly exit.. but i think your solution here is fine. maybe make the return value boolean.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, but I'll wait for @piscisaureus to review.
Closes #936
Rationale see #936 comments (handler implementation moved to TS side).
v8 emits
kPromiseHandlerAddedAfterReject
when a catch block is found in async function, that cancels a previouskPromiseRejectWithNoHandler
. Postpone error handling and exit to the end of each event loop cycle.tests/async_error.ts.out
actually now matches that running under Node. ("world" is printed first: error handling only happens after script running to its end)An alternative C++ only implementation could be found here