-
-
Notifications
You must be signed in to change notification settings - Fork 5.1k
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
$router.push() followed by redirect in a route's beforeEnter hook causes uncaught promise rejection #2932
Comments
I already answered this at #2833 (comment)
Please, check the related issues, the reasoning has been verbosely explained there already |
@posva I did read your previous reply and the referenced issue #2881 in its entirety. Here's why I thought this issue is different in more detail:
I spent quite some time debugging, researching and reproducing this in a minimal test case and I honestly thought this issue was different from the others linked. Note also that, in an attempt to not add noise to the repo, my first step was to find another related issue and not hastily create a new one :). Of course all these issues are related to |
For reference, here is the concrete use-case from my application:
|
After reading through the other issues, I believe I'm in the same boat as @berniegp. A navigation guard that redirects results in the console error. To confirm for my own sanity, I used vue cli to generate a project and then updated router.js with a third (valid) route that has a guard which will always redirect back to the root page:
About.vue component is updated with a button that, when clicked, sends you to the new component:
The call to Am I correct in understanding the proposed solution is to have all calls to
That does suppress any console error. But is that the desired behavior? |
Any navigation failure is a promise rejection. I updated my comment at #2881 (comment) that explains everything. Let me know if there is anything to add Some errors haven't been changed yet and that's why the uncaught error may be |
Just to be clear and to make sure I'm not misunderstanding anything: Are you saying that what we see now is a known "navigation error", generated by a defect in vue router, that was just never exposed? In other words, my example above is a redirect from one valid path to another valid path with nothing else happening. There are no errors except the one reported by the router, which itself seems to be an error. |
I see. This is a case of my misunderstanding what counts as a "navigation failure". The language used seems a bit off IMO, but I understand now. |
@posva Thanks for the clarification! However, I would argue that a redirection that cancels a navigation should not be a Promise rejection. Since rejection becomes a throw in the async/await model, it should only occur on actual errors. In my opinion, an expected control flow with a redirection should not have to add error handlers to avoid errors. While reading #2881 and the relevant documentation again, I could not find a description of what The example code you gave in #2881 inspired me to create this global const router = new VueRouter({ /* ... */ });
const originalPush = router.push;
router.push = function push(location, onResolve, onReject) {
if (onResolve || onReject) {
return originalPush.call(this, location, onResolve, onReject);
}
return originalPush.call(this, location).catch((err) => {
if (err) {
// If there really is an error, throw it
// Should probably be more sophisticated based on the type of err
return Promise.reject(err);
}
// Otherwise resolve to false to indicate the original push call didn't go to its original
// destination.
// TODO: return the final route instead of false?
return Promise.resolve(false);
});
}; Since the precise resolve/reject behavior of |
Have the same problem. I have another question I have big project and now I should |
This comment has been minimized.
This comment has been minimized.
My main question is that if the router throws an exception, does it mean the users (me/us) are doing something wrong? If not, then I think it's unwarranted. For example, @richterdennis proposed a |
v3.0.7 looks good! I also think this bug is another. |
I was still getting uncaught promise rejection errors in the chrome debugger, even when calling router.push('/').then(e => {}), and I think I figured out the (subtle!) source of the bug. vue-router/dist/vue-router.esm.js Line 2786 in 0c2b1aa
This line here creates a new promise that immediately runs. The result of that is that any .catch() you may have on the outside hasn't attached yet, as the push() call has not returned yet.
Looking at the frame in question vue-router/dist/vue-router.esm.js Line 2060 in 0c2b1aa
the onAbort being called here (synchronously) is the default reject from the promise all the way back in the first snippet!
Wrapping the push call with a timeout like so solves the unhandled rejection, as the VueRouter.prototype.push = function push (location, onComplete, onAbort) {
var this$1 = this;
// $flow-disable-line
if (!onComplete && !onAbort && typeof Promise !== 'undefined') {
return new Promise(function (resolve, reject) {
setTimeout(() => this$1.history.push(location, resolve, reject), 0);
})
} else {
this.history.push(location, onComplete, onAbort);
}
}; |
Also fixed uncaught exceptions when redirecting with `router.push`, see vuejs/vue-router#2932
This comment has been minimized.
This comment has been minimized.
This RFC improves navigation failures and should address some of the problems people were facing regarding the uncaught promise rejections: vuejs/rfcs#150 |
fact: This error is occurred by aborting a pending navigation. Reason: The first router initialization might override first bridge calling. We use a callback queue to delay all navigations until router initialization completed. - https://github.com/vuejs/vue-router/blob/v3.2.0/src/history/base.js#L187-L189 - vuejs/vue-router#2932 - https://stackoverflow.com/questions/57897511/in-vue-router-why-would-this-happen-this1-pending-route
try to catch the error.
|
Version
3.1.3
Reproduction link
https://jsfiddle.net/asu3qnry/
Steps to reproduce
To trigger the uncaught promise rejection, click on "/home" and then the button.
What is expected?
No uncaught promise rejection because there are actually no errors generated by the application. It's simply a navigation (
$router.push
) that generates a redirect (next('/foo')
) in abeforeEnter
hook.What is actually happening?
Console reports:
Uncaught (in promise) undefined
Using a
router-link
to/bar
instead of the initial$router.push('/bar')
does not produce the error.Related to #2833 #2881
The text was updated successfully, but these errors were encountered: