Vue的路由在執行跳轉時,根據源碼可知,調用了router中定義的navigate函數,源碼中可以看出,由Promise then的鏈式調用保證了路由守衛按照以下順序執行 ...
Vue的路由在執行跳轉時,根據源碼可知,調用了router中定義的navigate函數
function push(to: RouteLocationRaw) {
return pushWithRedirect(to)
}
function replace(to: RouteLocationRaw) {
return push(assign(locationAsObject(to), { replace: true }))
}
function pushWithRedirect(
to: RouteLocationRaw | RouteLocation,
redirectedFrom?: RouteLocation
): Promise<NavigationFailure | void | undefined> {
// ...
return (failure ? Promise.resolve(failure) : navigate(toLocation, from))/*調用navigate*/
.catch((error: NavigationFailure | NavigationRedirectError) =>
isNavigationFailure(error)
? // navigation redirects still mark the router as ready
isNavigationFailure(error, ErrorTypes.NAVIGATION_GUARD_REDIRECT)
? error
: markAsReady(error) // also returns the error
: // reject any unknown error
triggerError(error, toLocation, from)
)
.then((failure: NavigationFailure | NavigationRedirectError | void) => {
if (failure) {
// ...
} else {
// 執行finalizeNavigation完成導航
// if we fail we don't finalize the navigation
failure = finalizeNavigation(
toLocation as RouteLocationNormalizedLoaded,
from,
true,
replace,
data
)
}
// 觸發`afterEach`
triggerAfterEach(
toLocation as RouteLocationNormalizedLoaded,
from,
failure
)
return failure
})
}
function navigate(
to: RouteLocationNormalized,
from: RouteLocationNormalizedLoaded
): Promise<any> {
let guards: Lazy<any>[]
// ...
// run the queue of per route beforeRouteLeave guards
return (
// 1.調用離開組件的`beforeRouteLeave`鉤子
runGuardQueue(guards)
.then(() => {
// 獲取全局的的`beforeEach`鉤子
// check global guards beforeEach
guards = []
for (const guard of beforeGuards.list()) {
guards.push(guardToPromiseFn(guard, to, from))
}
guards.push(canceledNavigationCheck)
// 2.調用全局的`beforeEach`鉤子
return runGuardQueue(guards)
})
.then(() => {
// 獲取更新的路由其對應組件的`beforeRouteUpdate`鉤子
// check in components beforeRouteUpdate
guards = extractComponentsGuards(
updatingRecords,
'beforeRouteUpdate',
to,
from
)
for (const record of updatingRecords) {
record.updateGuards.forEach(guard => {
guards.push(guardToPromiseFn(guard, to, from))
})
}
guards.push(canceledNavigationCheck)
// 3.調用復用組件的`beforeRouteUpdate`鉤子
// run the queue of per route beforeEnter guards
return runGuardQueue(guards)
})
.then(() => {
// 獲取進入的路由自身的`beforeEnter`鉤子
// check the route beforeEnter
guards = []
for (const record of enteringRecords) {
// do not trigger beforeEnter on reused views
if (record.beforeEnter) {
if (isArray(record.beforeEnter)) {
for (const beforeEnter of record.beforeEnter)
guards.push(guardToPromiseFn(beforeEnter, to, from))
} else {
guards.push(guardToPromiseFn(record.beforeEnter, to, from))
}
}
}
guards.push(canceledNavigationCheck)
// 4.調用新匹配路由的`beforeEnter`鉤子
// run the queue of per route beforeEnter guards
return runGuardQueue(guards)
})
.then(() => {
// NOTE: at this point to.matched is normalized and does not contain any () => Promise<Component>
// clear existing enterCallbacks, these are added by extractComponentsGuards
to.matched.forEach(record => (record.enterCallbacks = {}))
// 獲取進入的路由其對應組件的`beforeRouteEnter`鉤子
// check in-component beforeRouteEnter
guards = extractComponentsGuards(
enteringRecords,
'beforeRouteEnter',
to,
from
)
guards.push(canceledNavigationCheck)
// 5.調用新組件的`beforeRouteEnter`鉤子
// run the queue of per route beforeEnter guards
return runGuardQueue(guards)
})
.then(() => {
// 獲取全局的的`beforeResolve`鉤子
// check global guards beforeResolve
guards = []
for (const guard of beforeResolveGuards.list()) {
guards.push(guardToPromiseFn(guard, to, from))
}
guards.push(canceledNavigationCheck)
// 6.調用全局的`beforeResolve`守衛
return runGuardQueue(guards)
})
// catch any navigation canceled
.catch(err =>
isNavigationFailure(err, ErrorTypes.NAVIGATION_CANCELLED)
? err
: Promise.reject(err)
)
)
}
// 觸發`afterEach`
function triggerAfterEach(
to: RouteLocationNormalizedLoaded,
from: RouteLocationNormalizedLoaded,
failure?: NavigationFailure | void
): void {
// navigation is confirmed, call afterGuards
// TODO: wrap with error handlers
afterGuards
.list()
.forEach(guard => runWithContext(() => guard(to, from, failure)))
}
由上述源碼中可以看出,由Promise then的鏈式調用保證了路由守衛按照以下順序執行:
- 舊的路由組件
beforeRouteLeave
- 全局配置的
beforeEach
- 復用的路由組件
beforeRouteUpdate
- 新路由的
beforeEnter
- 新路由組件的
beforeRouteEnter
- 全局配置的
beforeResolve
- navigate執行完畢後,會調用
triggerAfterEach
函數,觸發afterEach
和官網文檔上所寫的是一樣的。The Full Navigation Resolution Flow
本文來自博客園,作者:beckyye,轉載請註明原文鏈接:https://www.cnblogs.com/beckyyyy/p/17585702.html