vue-router钩子执行顺序

  • vue-router钩子执行顺序已关闭评论
  • 107 次浏览
  • A+
所属分类:Web前端
摘要

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的链式调用保证了路由守卫按照以下顺序执行:

  1. 旧的路由组件beforeRouteLeave
  2. 全局配置的beforeEach
  3. 复用的路由组件beforeRouteUpdate
  4. 新路由的beforeEnter
  5. 新路由组件的beforeRouteEnter
  6. 全局配置的beforeResolve
  7. navigate执行完毕后,会调用triggerAfterEach函数,触发afterEach

和官网文档上所写的是一样的。The Full Navigation Resolution Flow