javascript Uncaught (in promise) undefined - Vue-router

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/57493516/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 10:39:55  来源:igfitidea点击:

Uncaught (in promise) undefined - Vue-router

javascriptvue.jspromiseasync-awaitvue-router

提问by Dally

I'm facing a really strange issue where if a user with restricted permissions tries logging into my web app, they see the following error:

我面临一个非常奇怪的问题,如果具有受限权限的用户尝试登录我的网络应用程序,他们会看到以下错误:

Uncaught (in promise) undefined

Uncaught (in promise) undefined

But this doesn't happen with users who have max permissions.

但这不会发生在拥有最大权限的用户身上。

I think the issue is being caused by the re-reoute. If the user does not have page_access 1, it then routes to /holidays. The other strange thing is that this error only ever appears the once, and that's when the user first logs in. If the page is refreshed or the user navigates away to other pages, it does not appear.

我认为问题是由重新路由引起的。如果用户没有 page_access 1,则它会路由到 /holidays。另一个奇怪的事情是这个错误只出现一次,也就是用户第一次登录的时候。如果页面刷新或用户导航到其他页面,它不会出现。

router.js

路由器.js

Vue.use(Router)

const router = new Router({

  routes: [
    {
      path: '/',
      name: 'dashboard',
      component: Dashboard,
      beforeEnter(to, from, next) {
        if(localStorage.token) {
          if(localStorage.page_access.indexOf('1') != -1 && localStorage.page_access != null) {
            next('/holidays');
          }
          else {
            next();
          }
        } else {
          next('/login');
        }
      }
    },
    {
      path: '/holidays',
      name: 'holidays',
      component: Holidays,
      beforeEnter(to, from, next) {
        if(localStorage.token) {
          next();
        } else {
          next('/login');
        }
      }
    },
  ],
  mode: 'history'
})

router.beforeResolve((to, from, next) => {

  if(localStorage.token && from.name != 'login' && to.name != 'login') {
    store.dispatch('autoLogin')
    .then(response => {
      store.dispatch('getNavigation');
      next();
    })
    .catch(err => {
      console.log(err);
    });
  }
  else if(from.name && !localStorage.token) {
    router.go('/login');
  }
  else {
    next();
  }
});

export default router;

store.js

商店.js

async autoLogin({commit}) {
    const token = localStorage.getItem('token');
    const remember_token = localStorage.getItem('remember_token');

    if(!token) {
      return;
    }

    try {
      const res = await axios({
      method: 'post',
      data: { userId: localStorage.user_id, token: localStorage.remember_token },
      url: 'https://controlapi.totalprocessing.com/api/get-user',
      config: { headers: { 'Content-Type': 'application/x-www-form-urlencoded' }}
      })
      .then(response => {
        if(response.data.remember_token == remember_token) {
          commit('authUser', { token: token });
          return response;
        }
        else {
          localStorage.clear();
          return null;
        }
      })
      .catch(e => {
          this.errors.push(e);
          return e;
      })
      return res;
    }
    catch(e) {
      console.log(e);
      return e;
    }
}
getNavigation({commit}) {
    let pageAccess = localStorage.page_access == 'null' ? null : localStorage.page_access;
    let subPageAccess = localStorage.sub_page_access == 'null' ? null : localStorage.sub_page_access;

    axios({
    method: 'post',
    data: { pageAccess: pageAccess, subPageAccess: subPageAccess },
    url: 'https://controlapi.totalprocessing.com/api/client-get-navigation',
    config: { headers: { 'Content-Type': 'application/x-www-form-urlencoded' }}
    })
    .then(response => {
    console.log(response.data);
        const data = response.data;
        const tree = [];

        data.reduce(function(a, b, i, r) {

            // Add the parent nodes
            if(a.page_id != b.page_id){
                tree.push({ page_id: a.page_id,
                            page_name: a.page_name,
                            page_path: a.path,
                            page_icon: a.page_icon
                            });
            }

            // Add the last parent node
            if(i+1 == data.length) {
                tree.push({ page_id: b.page_id,
                            page_name: b.page_name,
                            page_path: b.path,
                            page_icon: b.page_icon
                            });

                // Add the child nodes to the parent nodes
                data.reduce(function(a, b) {
                    if(a.sub_page_id) {
                        const find = tree.findIndex(f => f.page_id == a.parent_id);

                        // Add the first child node to parent
                        if(!("children" in tree[find])) {
                            tree[find].children = [];

                            tree[find].children.push({ page_id: a.sub_page_id,
                                                    page_name: a.sub_page_name,
                                                    page_path: a.sub_page_path,
                                                    page_icon: a.sub_page_icon
                            });
                        }
                        // Add the remaining child nodes to parent nodes
                        else {
                            tree[find].children.push({ page_id: a.sub_page_id,
                                                    page_name: a.sub_page_name,
                                                    page_path: a.sub_page_path,
                                                    page_icon: a.sub_page_icon
                            });
                        }
                    }
                    return b;
                });
            }
            return b;
        });

        commit('authNav', {
        navigation: tree
        });
    })
    .catch(e => {
        this.errors.push(e)
    })
}

回答by agm1984

Based on my experience over the past few days, it is critical to catch errors in the function that calls this.$router.push().

根据我过去几天的经验,在调用this.$router.push().

I find two ways are immediately quite viable:

我发现有两种方法非常可行:

handleSomething() {
    this.$router.push({}).catch((err) => {
        throw new Error(`Problem handling something: ${err}.`);
    });
},

and

async handleSomething() {
    try {
        await this.$router.push({});
    } catch (err) {
        throw new Error(`Problem handling something: ${err}.`);    
    }
},

At the moment, I prefer against the async/await technique here because of its execution-blocking nature, but the key observation you should make is that the "uncaught in promise" error itself is a known issue in JavaScript often referred to as "a promise being swallowed", and it's caused by a Promise being rejected but that "error" is swallowed because it isn't properly caught. That is to say there is no block of code that catches the error, so your app cannot do anything in response to the error.

目前,我更喜欢这里的 async/await 技术,因为它具有执行阻塞的性质,但你应该做的关键观察是“uncaught in promise”错误本身是 JavaScript 中的一个已知问题,通常被称为“a承诺被吞下”,这是由 Promise 被拒绝引起的,但由于没有正确捕获“错误”而被吞下。也就是说,没有捕获错误的代码块,因此您的应用程序无法对错误进行任何响应。

This means it is paramount to not swallow the error, which means you need to catch it somewhere. In my two examples, you can see the error will pass through the catch blocks.

这意味着最重要的是不要吞下错误,这意味着您需要在某处捕获它。在我的两个示例中,您可以看到错误将通过 catch 块传递。

Secondary to the error swallowing, is the fact that the error is even thrown to begin with. In my application where I saw this, it was hard to debug, but I can see the nature of the error has something to do with Vue components unloading and loading as the route changes. For example, if you call this.$router.push()in a component and then that component gets destroyed while the route-change is in-progress, it is reasonable that you could see an error like this.

错误吞咽的次要事实是错误甚至一开始就被抛出。在我看到这个的应用程序中,很难调试,但我可以看到错误的性质与 Vue 组件随着路由的变化卸载和加载有关。例如,如果您调用this.$router.push()一个组件,然后该组件在路由更改正在进行时被销毁,那么您可能会看到这样的错误是合理的。

As an extension of this problem, if a route-change occurs and the resultant component tries to read data from the .push()event before the Promise is resolved, it could also throw this error. The awaitshould stop an error like that by instructing your application to wait before reading.

作为此问题的扩展,如果发生路由更改并且结果组件尝试.push()在 Promise 解决之前从事件中读取数据,它也可能抛出此错误。本await应通过指导你的应用程序读取之前等待停止这样的错误。

So in short, investigate those two things:

简而言之,调查这两件事:

  1. are you somehow destroying/creating components while this.$router.push()is executing?
  2. is the next component possibly reading data about route parameters before the route-change is completed?
  1. 您是否在this.$router.push()执行时以某种方式销毁/创建组件?
  2. 下一个组件是否可能在路由更改完成之前读取有关路由参数的数据?

If you discover some of this could be happening, consider your data flow and make sure you solve it by taming the async behaviour, not just by suppressing the error. In my opinion, the error is a symptom of something bigger.

如果您发现其中一些可能正在发生,请考虑您的数据流并确保您通过控制异步行为来解决它,而不仅仅是通过抑制错误。在我看来,错误是更大的征兆。

During your debugging, add console.log()s into all your components' created/mountedand destroyedlifecycle methods, and also into the functions related to the route change. You should be able to get a grasp on the way data is flowing.

在调试期间,将console.log()s添加到所有组件created/mounteddestroyed生命周期方法中,以及与路由更改相关的函数中。您应该能够掌握数据的流动方式。

I suspect the nature of this issue stems from downstream usage of this.$route.paramsduring an in-flight route-change. Add lots of console.logs and/or step through a debugger.

我怀疑这个问题的性质源于this.$route.params在飞行路线更改期间的下游使用。添加大量 console.logs 和/或单步调试调试器。

回答by mcmimik

In my case I just needed to add a catchto the router.pushmethod:

在我的情况下,我只需要catchrouter.push方法中添加一个:

router.push({query: newQueryObj)}).catch(e => {})

See this related issuefor more details.

有关更多详细信息,请参阅此相关问题

回答by at0dd

I also came across this issue and changing !variableto variable !==in the router did the trick.

我也遇到了这个问题,在路由器中更改!variable为可以解决问题variable !==

else if(from.name && !localStorage.token) {
    router.go('/login');
}

to

else if(from.name && localStorage.token === '') {
    router.go('/login');
}

回答by enso

add main.js;

添加 main.js;

import Router from 'vue-router'
const routerPush = Router.prototype.push
Router.prototype.push = function push(location) {
  return routerPush.call(this, location).catch(error=> error)
}

or; npm i [email protected] -S

或者; npm i [email protected] -S

回答by hanpanpan

Our problem is the same. You can jump to this path on the login page and write:

我们的问题是一样的。你可以在登录页面跳转到这个路径写:

this.$router.push({ path: this.redirect || '/' }, onComplete => { }, onAbort => { })

The wrong way to write is:

错误的写法是:

 this. $router. Push ({path: this. Redirect | '/'})