-
Notifications
You must be signed in to change notification settings - Fork 24.4k
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
JS exceptions are hidden from developer when using Promises (async functions) #4045
Comments
|
I like this idea a lot. @javache, @martinbigio Do you agree? |
I like the idea too. When I thought about this before (for ObjC PromiseKit) I concluded that the promise library should check if it has an unhandled error when the promise has been deallocated (this is the only time we know that no code can add an error handler to it). So I don't think it is possible to come up with a pure JS solution that is accurate. The good news is that in RN we can likely use the native JSC API to learn when promise objects have been deallocated, but it may require some ingenuity. |
That would be great! |
Summary: In accordance with the unwritten rule that any API that takes a callback should also return a promise, I've changed `InteractionManager.runAfterInteractions()` to do just that. ```js InteractionManager.runAfterInteractions(() => { ... }); ``` can become ```js InteractionManager.runAfterInteractions().then(() => { ... }); ``` (but doesn't have to). Most importantly, though, this change enables code like ```js doSomeUIStuff(); await InteractionManager.runAfterInteractions(); doSomeNonUIStuff(); ``` which is nice. Note: Because returning a `Promise` means the callback argument is now optional, the behaviour of the API is slightly changed, though not in a backwards-incompatible way (unless a consumer is in some way relying on the exception, but that would be insane). Closes #3788 Reviewed By: vjeux Differential Revision: D2634693 Pulled By: josephsavona fb-gh-sync-id: 7315120963be23cf69d777e940b2750d32ae47a8
Hm, I think we can do it, but maybe I’m too naive:
|
A promise can be rejected and then handled later, which is why we want to learn when the programmer is done with the promise. That is, I believe (1.i) is nuanced. It's going to be really noisy if the promise library warns about potential errors that are properly handled later. False positives in such a core language feature are frustrating. For example:
If you call this with an http URL, the constructed promise has already been rejected but we obviously don't want to warn because someone could add a catch handler to the rejected promise later -- maybe right away, maybe a few ticks from now. So |
|
Say you wanted to prefetch some data for the next screen. You might write code like this: componentDidMount() {
this.prefetchedDataPromise = fetch(...);
}
onNavigateToNextScreen() {
this.prefetchedDataPromise.then(data => ..., error => {
// fetch again or maybe just show a network error
});
} The cheap workaround is to add a no-op error handler: this.prefetchedDataPromise = fetch(...);
this.prefetchedDataPromise.catch(error => {}); The downsides are that now we're back a square one and won't get an error message if the programmer forgets to add a real error handler to the promise, and this doesn't address third-party code that doesn't handle rejected promises right away. If it were possible to tell the devtools to ignore unhandled promises in specific swaths of code, the latter point wouldn't be a problem, though. It might end up being totally fine in practice, especially if this becomes standard behavior, de facto or officially. |
I might play around with Chrome a little bit to see how it behaves (it logs unhandled rejections). If we can create a superior solution on the native side, let’s do it. Solving it in JS just wouldn’t require us to write and maintain two solutions. |
Can we solve the problem of missing |
Maybe I am dreaming here but it could be: "if promise is not returned by method than it must be |
Also Firefox outputs warning if an exception is silent in a Promise, this seems to be a native feature. |
Chrome has it, I just checked it. |
Yeah, this code prints error to log:
This one not because promise has error handling:
|
Linters won't work because not everyone uses a linter. |
I thought about the deallocation idea, and it has the same problem as warning on unhandled rejections: There might be unhandled rejections that are legitimately deallocated. |
@davidaurelio The fix for unhandled rejections that have been deallocated would be to add
OK. This seems like a good place to start. It's nice that it's deterministic unlike deallocation. |
Absolutely, that's the desired behaviour IMHO. But I thought Babel's Promise polyfill already did that? It does at least for me, but then again, I don't use the React Native packager -- I use webpack + a babel loader via https://github.com/mjohnston/react-native-webpack-server/. |
Someone had a good idea in the AMA today to have uncaught errors get fed into a global JS error handler. Then you could hook up the redbox to the global handler, or a custom handler as well. |
So, I get to see a redbox due to this Is this not triggering for anybody? If not, I wonder why. In any case, I support doing whatever we can to preserve the original stack (instead of having |
I’m on it, but will turn on yellow boxes first |
I've written the changes needed to track unhandled rejections in promise. If a few people want to review then/promise#116 I'll merge and release a new version. It should then be fairly simple for someone to buidl the yellowbox into react-native. It shouldn't be redbox because of the high probability of false-positives. Ideally the yellow box should be updated with a method to turn it green and indicate that the report was a false-positive. |
As for API: promise vs callbacks. |
You could, but promises are the better option. If you want to do that, you can just use |
👍 |
@ForbesLindesay We can't really do that, because the RN APIs are too different ATM - #4971 But I'm all for adding promise based APIs and eventually fading out the non-promise APIs. |
Summary: Adds support for tracking unhandled rejections with `console.warn` (= yellow box). I will create a follow-up with proper error stack formatting. related: facebook#4971 fixes: facebook#4045, facebook#4142 public {F59857438} {F59857439} Reviewed By: bestander Differential Revision: D2803126 fb-gh-sync-id: 376b33e42a967675a04338cbff3ec315a77d1037
@davidaurelio , thanks for adding this support (a long time ago)! Are there any "hooks" that will allow custom behavior when this occurs? I understand that there may be a probability for false positives, but in my experience with my own apps so far, unhandled promise rejections are typically a development error. Having an event or other "hook" would allow developers to choose how to handle this scenario (yellow box, red box, etc). |
you should be able to paste this code into your app, and throw an error: react-native/Libraries/Promise.js Lines 17 to 49 in c6b96c0
In case this does nothing, use |
Take the following example, which (correctly) produces a redbox:
The Java signature is:
Now change this to an async function:
No redbox is shown and nothing is logged which is in my opinion very poor developer experience. We've all been there - you're trying to debug a program which doesn't work but since there are no error messages and you have no idea what's wrong.
The way to "fix" this is to call
done()
:But this is super easy to forget :(
For now, I'll go with a callback in the
IntentAndroid
. Feel like we need to find a good solution to this problem first before we migrate all APIs to async functions.The text was updated successfully, but these errors were encountered: