Dal*_*lly 18 javascript promise async-await vue.js vue-router
我面临一个非常奇怪的问题,如果具有受限权限的用户尝试登录我的网络应用程序,他们会看到以下错误:
Uncaught (in promise) undefined
但这不会发生在拥有最大权限的用户身上。
我认为问题是由重新路由引起的。如果用户没有 page_access 1,则路由到 /holidays。另一个奇怪的事情是这个错误只出现一次,也就是用户第一次登录的时候。如果页面刷新或用户导航到其他页面,它不会出现。
路由器.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;
Run Code Online (Sandbox Code Playgroud)
商店.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;
}
}
Run Code Online (Sandbox Code Playgroud)
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)
})
}
Run Code Online (Sandbox Code Playgroud)
agm*_*984 19
根据我过去几天的经验,在调用this.$router.push().
我发现有两种方法非常可行:
handleSomething() {
this.$router.push({}).catch((err) => {
throw new Error(`Problem handling something: ${err}.`);
});
},
Run Code Online (Sandbox Code Playgroud)
和
async handleSomething() {
try {
await this.$router.push({});
} catch (err) {
throw new Error(`Problem handling something: ${err}.`);
}
},
Run Code Online (Sandbox Code Playgroud)
目前,我更喜欢这里的 async/await 技术,因为它具有执行阻塞的性质,但你应该做的关键观察是“uncaught in promise”错误本身是 JavaScript 中的一个已知问题,通常被称为“a承诺被吞下”,这是由 Promise 被拒绝引起的,但由于没有正确捕获“错误”而被吞下。也就是说,没有捕获错误的代码块,因此您的应用程序无法对错误进行任何响应。
这意味着最重要的是不要吞下错误,这意味着您需要在某处捕获它。在我的两个示例中,您可以看到错误将通过 catch 块传递。
错误吞咽的次要事实是错误甚至一开始就被抛出。在我看到这一点的应用程序中,很难调试,但我可以看到错误的性质与 Vue 组件在路由更改时卸载和加载有关。例如,如果您调用this.$router.push()一个组件,然后该组件在路由更改正在进行时被销毁,那么您可能会看到这样的错误。
作为此问题的扩展,如果发生路由更改并且结果组件尝试.push()在 Promise 解决之前从事件中读取数据,它也可能抛出此错误。本await应通过指导你的应用程序读取之前等待停止这样的错误。
简而言之,调查这两件事:
this.$router.push()执行时以某种方式销毁/创建组件?如果您发现其中一些可能正在发生,请考虑您的数据流并确保您通过控制异步行为来解决它,而不仅仅是通过抑制错误。在我看来,错误是更大的征兆。
在调试期间,将console.log()s添加到所有组件created/mounted和destroyed生命周期方法中,以及与路由更改相关的函数中。您应该能够掌握数据的流动方式。
我怀疑此问题的性质源于this.$route.params在飞行路线更改期间的下游使用。添加大量 console.logs 和/或逐步调试调试器。
就我而言,我只需要catch在router.push方法中添加一个:
router.push({query: newQueryObj)}).catch(e => {})
Run Code Online (Sandbox Code Playgroud)
有关更多详细信息,请参阅此相关问题。
小智 3
我也遇到了这个问题,并在路由器中更改!variable为variable !==成功。
else if(from.name && !localStorage.token) {
router.go('/login');
}
Run Code Online (Sandbox Code Playgroud)
到
else if(from.name && localStorage.token === '') {
router.go('/login');
}
Run Code Online (Sandbox Code Playgroud)