异步请求该放到哪个生命周期?

6,070 阅读4分钟

经常有人会问:Ajax这种异步请求,是放到created生命周期呢?还是放到mounted生命周期呢? 我近几个月没有写vue,突然也产生了这种疑惑,因为我说服不了自己created或者mounted是不能做异步请求的,现在我终于又一个相对全面的答案了,我来具体解答这个问题。

首先,我们应当把可选的生命周期范围扩大,并不是只有createdmounted这2个后渲染,我们还可以有更多。 我目前的候选人有6个,分别是:beforeCreatecreatedbeforeMountmountedbeforeUpdateupdated。 我们知道,每个生命周期函数实际上是一个钩子函数,意味着它们会在特定的情况下触发被调用。而它们有一定的触发顺序,如上面列出的,每个生命周期函数开始被调用的时间是按照上面列出的从前往后排序的(还有部分生命周期未列出)。 剩下未列出的生命周期函数有:activated、deactivated、beforeDestroy、destroyed、errorCaptured,其中activated、deactivated是用在组件使用keep-alive的时候调用,而beforeDestroy、destroyed是在组件销毁前和销毁的时候触发,errorCaptured在存在错误时可以去使用,它们都和Ajax异步请求八竿子打不着。 至于剩下6个候选者,我们还可以排除一些,beforeUpdate是在数据更新的时候被调用,而updated是在数据更新导致dom渲染完成后调用,它们被调用的时候数据已经改变了,并不适合去请求异步数据;而beforeCreate被调用的时候,data还没有挂载,我们可以在这个钩子函数里面去做一些初始化dom的操作,而不是异步请求,beforeMount是在模板实例挂载之前被调用,是可以执行异步请求的,但是mounted也可以实现,而且在mounted被调用时候,模板实例已经挂载,更适合做一些与dom相关的操作。

上面说了那么多,排除了其他生命周期函数,就剩下了createdmounted,那么我们该用哪个去做异步请求呢? 我的答案是:都可以。更严谨的答案是:大多数情况两者都可以,对于特定情况,需要选择性使用两者之一。

那么,**为什么它们都可以?**这个一个很好的问题,因为有这个疑问的你不想只是接受结论,而是想要知道结论是如何得出的。

首先,我们知道各个生命周期函数被调用的时间是由先后顺序,但是它们执行完毕的顺序是不确定的;如果函数内部存在着异步代码,那么函数执行完毕的时间就不能确定。 其次,Vue的生命周期函数中,只有beforeUpdateupdated是会因为dom变化重新渲染而被多次调用的,其余的在一个组件中只会触发一次。这意味着,其实created只是比mounted早一点被调用,同样的异步代码在两者中执行完毕后的结束时间不会差太多,因为虚拟dom的渲染是在异步进行的,不会影响两者。所以对于一般的数据请求,在created或者mounted执行区别不大,它们都可以执行异步请求。

最终结论来了,我们到底该在什么情况下选择created,而又在什么情况下选择updated?

  1. 对于作为子组件被调用的组件里,异步请求应当在mounted里调用,因为这个时候子组件可能需要涉及到对dom的操作;
  2. 对于页面级组件,当我们需要使用ssr(服务端渲染)的时候,只有created是可用的,所以这个时候请求数据只能用它;
  3. 对于页面级组件, 当我们做异步操作时,涉及到要访问dom的操作,我们仍旧只能使用mounted;
  4. 对于一般情况,createdmounted都是可以的;

补充一点,在mounted被调用时,vue不保证子组件也都被挂载完毕了,所以如果希望整个视图渲染完毕再执行操作,需要使用$nexttick,使用方法如下:

mounted: function () {
  this.$nextTick(function () {
    // Code... 
  })
}

$nexttick`本身会接收一个回调函数,它实际上会让里面的代码延时执行,类似于setTimeout。

根据上面的结论,我们知道大多数情况下,使用createdmounted做异步请求没什么区别,但是对于上面提到的几种情况需要选择其中之一。我的个人习惯是:对于页面级组件,一般在created里调用,这样做是为了与子组件里需要在mounted里调用做一个区分,便于提醒这个知识点。