Copy function navigate(
to: RouteLocationNormalized,
from: RouteLocationNormalizedLoaded
): Promise<any> {
// 1. 提取路由记录 RouteRecord
const [leavingRecords, updatingRecords, enteringRecords] = extractChangingRecords(to, from)
// 2. guards.push()
let guards: Lazy<any>[]
// 这里所有的组件都已经被 resolved 了一次,因为我们 are leaving
guards = extractComponentsGuards(
leavingRecords.reverse(), // 原地操作,反转
'beforeRouteLeave',
to,
from
)
for (const record of leavingRecords) {
record.leaveGuards.forEach(guard => {
guards.push(guardToPromiseFn(guard, to, from))
})
}
const canceledNavigationCheck = checkCanceledNavigationAndReject.bind(
null,
to,
from
)
guards.push(canceledNavigationCheck)
// 3. 运行每个 route 的 beforeRouteLeave 守卫队列
return (
runGuardQueue(guards)
.then(() => {
// 检查全局守卫, beforeEach
guards = []
for (const guard of beforeGuards.list()) {
guards.push(guardToPromiseFn(guard, to, from))
}
guards.push(canceledNavigationCheck)
return runGuardQueue(guards)
})
.then(() => {
// 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)
// 运行每个 route 的 beforeEnter 守卫队列
return runGuardQueue(guards)
})
.then(() => {
// 检查 route 的 beforeEnter
guards = []
for (const record of to.matched) {
// 对于 reused views,不触发 beforeEnter
if (record.beforeEnter && !from.matched.includes(record)) {
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)
// 运行每个 route 的 beforeEnter 守卫队列
return runGuardQueue(guards)
})
.then(() => {
// 注意:此时 to.matched 已被规范化,且不包含任何 () => Promise<Component>
// 清除现有的 enterCallbacks, 它们是由 extractComponentsGuards 添加的
to.matched.forEach(record => (record.enterCallbacks = {}))
// check in-component beforeRouteEnter
guards = extractComponentsGuards(
enteringRecords,
'beforeRouteEnter',
to,
from
)
guards.push(canceledNavigationCheck)
// 运行每个 route 的 beforeEnter 守卫队列
return runGuardQueue(guards)
})
.then(() => {
// 检查全局守卫, beforeResolve
guards = []
for (const guard of beforeResolveGuards.list()) {
guards.push(guardToPromiseFn(guard, to, from))
}
guards.push(canceledNavigationCheck)
return runGuardQueue(guards)
})
// catch 所有取消的any navigation
.catch(err =>
isNavigationFailure(err, ErrorTypes.NAVIGATION_CANCELLED)
? err
: Promise.reject(err)
)
)
}
function runGuardQueue(guards: Lazy<any>[]): Promise<void> {
return guards.reduce(
(promise, guard) => promise.then(() => guard()),
Promise.resolve()
)
}