未捕获(承诺)未定义-Vue路由器

时间:2019-08-14 11:07:57

标签: javascript vue.js promise async-await vue-router

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

Uncaught (in promise) undefined

但是具有最大权限的用户不会发生这种情况。

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

router.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

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)
    })
}

5 个答案:

答案 0 :(得分:1)

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

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

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

答案 1 :(得分:1)

根据我过去几天的经验,在调用this.$router.push()的函数中发现错误至关重要。

我发现两种方法立即可行:

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

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

此刻,由于它具有执行阻塞的性质,因此我在这里不推荐使用async / await技术,但是您应该进行的主要观察是,“未捕获的承诺”错误本身是JavaScript中经常提到的已知问题。表示“吞没了诺言”,这是由于Promise被拒绝而造成的,但是“错误”被吞没了,因为没有正确抓住它。也就是说,没有代码块可以捕获该错误,因此您的应用无法响应该错误。

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

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

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

因此,简而言之,请研究这两件事:

  1. 您是否在执行this.$router.push()的同时破坏/创建组件?
  2. 下一个组件是否可能在路线更改完成之前读取有关路线参数的数据?

如果发现其中某些情况可能发生,请考虑一下数据流,并确保通过驯服异步行为来解决问题,而不仅仅是抑制错误。在我看来,错误是更大的症状。

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

我怀疑此问题的性质是由于在进行空中航线更改期间this.$route.params的下游使用。添加大量console.logs和/或逐步调试。

答案 2 :(得分:1)

我们的问题是相同的。您可以在登录页面上跳至该路径并输入:

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

错误的书写方式是:

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

答案 3 :(得分:0)

对于我来说,我只需要向catch方法中添加一个router.push

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

有关更多详细信息,请参见此related issue

答案 4 :(得分:-1)

添加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)
}

或;     npm我vue-router@3.0 -S