-
Notifications
You must be signed in to change notification settings - Fork 15.8k
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
Allow web frame methods to return async promises #7533
Conversation
Would be great to get some spec coverage for this case. |
@kevinsawicki Added an async spec 👍 |
event.sender.send(`ELECTRON_INTERNAL_BROWSER_ASYNC_WEB_FRAME_RESPONSE_${requestId}`, resolvedResult) | ||
}) | ||
.catch((resolvedError) => { | ||
console.error(`An async web frame method (${method}) returned a promise that threw an error: `, resolvedError) |
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.
This Feels Bad, shouldn't it rethrow on the other side?
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'm not sure how it can rethrow. Because it is async you can't throw Error
as that would be uncatchable. And the standard callback syntax (err, result)
isn't in use here so switching to that would be a massive breaking change for anyone using executeJavaScript
.
We also currently allow syncronous errors to just fly through as uncaught exceptions in the renderer process so not sure how this is much different 👍
If we're OK with making the breaking change to the callback I'm happy to do that
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.
It seems like you could serialize the error, send it over the wire, then return a Promise.reject(new Error(thatError))
, no?
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.
So we want a callback that returns a rejected promise. I was under the impression that Promises didn't transition well across IPC though. I'll see if I can come up with a simple / nice way of doing this 👍
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.
@paulcbetts I just modified the code so that the callback syntax remains the same but the executeJavaScript
method now returns a promise that resolves the the result and rejects with any thrown error. Let me know if that works for you 👍
@@ -642,12 +642,26 @@ Injects CSS into the current web page. | |||
* `callback` Function (optional) - Called after script has been executed. | |||
* `result` | |||
|
|||
Returns `Promise` - A promise that resolves with the result of the executed code | |||
or is rejected if the result of the code is a rejected promise |
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.
Missing .
at end of sentence
var code = '(() => "' + expected + '")()' | ||
var asyncCode = '(() => new Promise(r => setTimeout(() => r("' + expected + '"), 500)))()' |
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.
Maybe we should switch these two new code strings and the existing code
variable to use template strings for clarity.
if (callback) callback(result) | ||
resolve(result) | ||
}) | ||
ipcMain.once(`ELECTRON_INTERNAL_BROWSER_ASYNC_WEB_FRAME_ERROR_${requestId}`, (event, error) => { |
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.
Hmm, so this event listener will hang around forever if the promise is never rejected, and the other one will hang around forever if the promise is rejected right?
Maybe we can use ELECTRON_INTERNAL_BROWSER_ASYNC_WEB_FRAME_RESPONSE_
for both cases and just have two arguments (event, result, error)
and reject when error is present and resolve otherwise with result.
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.
We could also (and probably should anyway) remove the event listener with .removeListener
once we have recieved the first response / first error
efb4865
to
11851f9
Compare
@kevinsawicki Just realized I hadn't updated this 😆 I think I addressed your comments 👍 |
1e4a787
to
8e20359
Compare
Thanks for this @MarshallOfSound 👍 |
Fixes #7532
Basically this handles
executeJavaScript
calls returning instances ofPromise
and resolving that promise before passing it back through IPC to the caller.This trick works because
It allows for truly asyncronous execution like so
This is non-blocking async execution 👍