react高阶面试题中有这么一道:为什么异步请求数据在didMount阶段更合适?同为MVVM中的翘楚,Vue是否也有类似问题呢?另外,我在平时也无开发过程中也会发现,每个人选择的那个生命周期阶段去异步请求数据总会不一样,因此引发思考,到底哪个阶段更适合异步请求数据呢?在产品设计和用户体验方面又会有哪些影响?本篇记录就是为了解决这两个问题。

一、Vue生命周期

首先再老话重提过一下Vue生命周期,以及每个阶段都做了什么事。

1. beforeCreated:生成$options选项,并给实例添加生命周期相关属性。在实例初始化之后,在 数据观测(data observer) 和event/watcher 事件配置之前被调用,也就是说,data,watcher,methods都不存在这个阶段。但是有一个对象存在,那就是$route,因此此阶段就可以根据路由信息进行重定向等操作。

2. created:初始化与依赖注入相关的操作,会遍历传入methods的选项,初始化选项数据,从$options获取数据选项(vm.$options.data),给数据添加‘观察器’对象并创建观察器,定义getter、setter存储器属性。在实例创建之后被调用,该阶段可以访问data,使用watcher、events、methods,也就是说 数据观测(data observer) 和event/watcher 事件配置 已完成。但是此时dom还没有被挂载。该阶段允许执行http请求操作。

3. beforeMount:将HTML解析生成AST节点,再根据AST节点动态生成渲染函数。相关render函数首次被调用(划重点)。

4. mounted:在挂载完成之后被调用,执行render函数生成虚拟dom,创建真实dom替换虚拟dom,并挂载到实例。可以操作dom,比如事件监听

5. beforeUpdate:$vm.data更新之后,虚拟dom重新渲染之前被调用。在这个钩子可以修改$vm.data,并不会触发附加的冲渲染过程。

6. updated:虚拟dom重新渲染后调用,若再次修改$vm.data,会再次触发beforeUpdate、updated,进入死循环。

7. beforeDestroy:实例被销毁前调用,也就是说在这个阶段还是可以调用实例的。

8. destroyed:实例被销毁后调用,所有的事件监听器已被移除,子实例被销毁。

总结来说,虚拟dom开始渲染是在beforeMount时,dom实例挂载完成在mounted阶段显示。

那么接下来了解就是render函数。

render示例:export default {data () {return {menu_items: []   // 请求返回如:[{fullname: '页面一'},{fullname: '页面二'},{fullname: '页面三'},{fullname: '页面四'}]}},   render (createElement){    return createElement(// 1. 第一个参数,要渲染的标签名称(必填)'ul',// 2. 第二个参数,1中要渲染的标签的属性,或者文本元素(可选)      {  class: {'uk-nav': true},           },          // 3. 第三个参数,1中标签的子元素,详情看官方文档(可选)this.menu_items.map(item=>createElement('li',item.fullname))))  }}复制代码

render函数最终返回的是createNodeDescription(节点描述),即俗称virtual node(虚拟节点)。用template写的话,就是下面这样:

<template><ul>       <li v-for="item in menu_items">         {{ item.fullname }}     </li>  </ul></template>复制代码

这个过程在mounted被调用前完成。详细参考可移步 这里

二、异步加载

setTimeout等异步函数

异步函数跟同步函数的不同之处,最大的应该就是异步函数会等到所有同步函数执行完成之后再执行。具体的可以看 事件循环 。

//data字段有个num
created: function () {console.group('created 创建完毕状态===============》')console.log('%c%s', 'color:red', 'el     : ' + this.$el) // undefinedconsole.log('%c%s', 'color:red', 'data   : ' + this.$data) // 已被初始化console.log('%c%s', 'color:red', 'message: ' + this.message) // 已被初始化//新增代码片段setTimeout(() => { //这里只是为了偷懒用了ES6的箭头函数,如果是普通函数请注意this指针修改,vue中请不要滥用箭头函数,出了问题找都找不到this.num ++this.num += 2}, 0) //注意这里的延时都是0setTimeout(() => {this.num -= 5}, 0)}复制代码

控制台答应结果:

(略失真。。。截图太大稍微压缩了下!!--)

vue在执行代码的时候,并没有去管定时器里发生了什么事情,甚至已经设置了0延时,他依旧会去顺序执行其他生命周期,看起来就像跳过了这些异步加载。因此可以确定一点,生命周期中的异步操作不会按照顺序执行,而是会等到非异步操作结束后执行。因此书写这部分代码的时候请注意里面的逻辑不要和顺序挂钩,要确保任何异步操作即使最后执行,之前的程序也不会发生异常从而阻塞整个进程。

ajax异步请求

ajax请求是异步操作,回调函数的执行时间是不确定的。也就是说,即使在created钩子发送请求,dom被挂载之后请求仍没有返回结果,就很有可能导致运行出错,诸如:

因为此时上述render事例中的menu_items还是空置。

解决方案

针对ajax异步请求,这样的错误原因其实就是因为返回结果没赶上dom节点的渲染。所以可以从两方面做修改:一是返回结果的赋值变量上,另一个就是dom节点的渲染层面。

1. 给予赋值变量初始值,即定义时menu_items:[ {fullname: ''} ]。

这么做的好处就是页面节点的渲染不受限于返回结果,静态文案照样会被渲染,动态数据则会在数据更新时被填充。给用户的感觉就是,页面渲染速度不错。

但是这种方式也有缺陷,后台返回数据字段不尽相同,要是都这么写那就真是麻烦了。

当然如果你使用typescript就没有这种烦恼,menu_items: { [propName: string]: any } = {}就搞定了。

2. v-if,控制dom节点的挂载,当且仅当menu_items被赋予返回值时,才开始渲染节点。

这么做的好处就是静态和动态文案同步展现在用户面前,不会有文案跳动,数据从无到有的过程。但是,副作用就是页面渲染时间、用户等待时间变长。

那如果dom挂载前请求数据已经返回了,又会是怎样的结果呢?

我们可以用setTimeout来模拟一下这个过程

<span>{{person.name.firstName}}</span> data: function () {return {message: 'hello world',add: 1,person: {name: {}}}},
created: function () {console.group('created 创建完毕状态===============》')console.log('%c%s', 'color:red', 'el     : ' + this.$el) // undefinedconsole.log('%c%s', 'color:red', 'data   : ' + this.$data) // 已被初始化console.log('%c%s', 'color:red', 'message: ' + this.message) // 已被初始化//假装接口返回了一些信息给你,如一个人,然后你把这些信息赋值给了this实力setTimeout(() => {this.person = {name: {lastName: 'carry',firstName: 'dong'},sex: '男'}}, 0)复制代码

请求够早了吧,但还是报错了,this.person.name.firstName 是 undefined,不过程序报完错后还是再继续执行了。

三、结论

既然异步函数并不会阻塞vue生命周期整个进程,那么在哪个阶段请求都可以。如果考虑到用户体验方面的影响,希望用户今早感知页面已加载,减少空白页面时间,建议就放在created阶段了,然后再处理会出现null、undefined这种情况就好。毕竟越早获取数据,在mounted实例挂载的时候渲染也就越及时。

当然即使是这种情况下,也不排除会触发updated生命钩子(data有默认值且已渲染,之后数据被更新),从而导致虚拟dom的重新渲染。

异步加载在Vue生命周期哪个阶段更合理相关推荐

  1. 【iOS开发】-UIViewController加载过程和生命周期

    文章目录 前言 ViewController执行过程的探讨 ViewControllerOne 函数介绍 顺序引入 ViewControllerSecond引入 ViewControllerOne点击 ...

  2. vue生命周期每个阶段可以做什么

    解析vue生命周期每个阶段都做什么 一.生命周期有哪些 在 vue 的创建.使用.销毁过程中,会有许多事件,这些事件就被统称为生命周期函数,也叫作生命周期钩子,有beforeCreate( 创建前 ) ...

  3. Android apk动态加载机制的研究(二):资源加载和activity生命周期管理

    转载请注明出处:http://blog.csdn.net/singwhatiwanna/article/details/23387079 (来自singwhatiwanna的csdn博客) 前言 为了 ...

  4. 类的加载过程(生命周期)

    一.概述 生命周期的7个阶段: 从使用过程看: 最后会在方法区,存在类的模版,之后就可以使用这个类了. 二.过程1:Loading阶段(加载) 所谓加载,就是将字节码文件加载到机器内存中,并在内存中构 ...

  5. 页面加载时,vue生命周期的触发顺序

    那么进入某个路由对应的组件的时候,我们会触发哪些类型的周期呢? 根实例的加载相关的生命周期(beforeCreate.created.beforeMount.mounted) 组件实例的加载相关的生命 ...

  6. vue进阶测试——生命周期和异步加载的微妙关系

    本文继续探索vue中的坑,关于vue的生命周期和异步加载相关处理的文章还比较少,可能是自己没有用谷歌而用百度的缘故吧.关于异步操作和生命周期,会牵扯到浏览器的单线程处理机制,以及ES中的promise ...

  7. Vue生命周期,Vue中在哪个生命周期阶段调用异步请求最佳

    Vue生命周期 beforeCreate(创建前): 在数据观测和初始化事件还未开始,data.watcher.methods都还不存在,但是$route已存在,可以根据路由信息进行重定向等操作. c ...

  8. 在Vue中异步加载数据渲染到Dom

    在Vue中异步加载数据渲染到Dom 问题 <div v-for="o in resmessage" :key="o" class="text i ...

  9. 关于Vue admin 框架中 Pagination 分页 异步加载的问题

    关于Vue admin 框架中 Pagination 分页 异步加载的问题 贴代码 核心代码: this.$emit('update:page', this.currentPage) this.$em ...

最新文章

  1. JavaScipt 中的事件循环(event loop),以及微任务 和宏任务的概念
  2. R语言:na.fail和na.omit
  3. 谭浩强课后题之----输入一行字符,统计英文字母,数字以及空格数量
  4. ant vue 设置中文_Ant Design Vue 添加区分中英文的长度校验功能
  5. 【转】sql表及字段命名规范
  6. python检验阿姆斯特朗数_python 之九九乘法表,润年,奇偶数,阿姆斯特朗数判断分享...
  7. git学习心得之从远程仓库克隆
  8. CI集成 ckeditor 配置
  9. 将m个苹果放入n个盘子的问题【转】
  10. 【报告分享】B站商业化探索频频,品牌方如何布局“小破站”营销.pdf
  11. Java基础篇:如何使用continue语句
  12. 海康摄像机、NVR、流媒体服务器、回放取流RTSP地址规则说明
  13. 【业余无线电BI1FKP】万里通UV5F-Plus写频、自制写频线
  14. 自增 ID 用完了怎么办 ?
  15. 人脸检测--libfacedetection
  16. python列重命名
  17. Python 获取 网易云音乐热门评论
  18. office2016 无法启动服务,原因可能是已被禁用或与其相关联的设备没有启动
  19. 数学笔记14——微积分第一基本定理
  20. delphi Base64 编解码

热门文章

  1. boost::hana::detail模块实现相关算法的测试程序
  2. boost::fusion::for_each用法的测试程序
  3. GDCM:gdcm::Directory的测试程序
  4. GDCM:转储一个DICOM文件,显示DICOM中的结构和值的测试程序
  5. boost::contract模块实现dictionary字典的测试程序
  6. ITK:单相Chan和Vese密集域水平集分割
  7. ITK:提取给定的标签对象
  8. VTK:可视化之BillboardTextActor3D
  9. VTK:PolyData之PointInsideObject2
  10. VTK:Parallel之ExodusIIWriter