一、定义[nextTick、事件循环]

  nextTick的由来:
    由于VUE的数据驱动视图更新,是异步的,即修改数据的当下,视图不会立刻更新,而是等同一事件循环中的所有数据变化完成之后,再统一进行视图更新。
  nextTick的触发时机:
    在同一事件循环中的数据变化后,DOM完成更新,立即执行nextTick(callback)内的回调。
  应用场景:
    需要在视图更新之后,基于新的视图进行操作。
  以上出现了事件循环的概念,其涉及到JS的运行机制,包括主线程的执行栈、异步队列、异步API、事件循环的协作,此处不展开之后再总结。大致理解:主线程完成同步环境执行,查询任务队列,提取队首的任务,放入主线程中执行;执行完毕,再重复该操作,该过程称为事件循环。而主线程的每次读取任务队列操作,是一个事件循环的开始。异步callback不可能处在同一事件循环中。
  简单总结事件循环:
    同步代码执行 -> 查找异步队列,推入执行栈,执行callback1[事件循环1] ->查找异步队列,推入执行栈,执行callback2[事件循环2]...
  即每个异步callback,最终都会形成自己独立的一个事件循环。
  结合nextTick的由来,可以推出每个事件循环中,nextTick触发的时机:
    同一事件循环中的代码执行完毕 -> DOM 更新 -> nextTick callback触发
   tips:本文的任务队列、消息队列、异步队列指同一个东西,均指macrotask queue。
       事件循环详解:http://www.cnblogs.com/hity-tt/p/6733062.html

二、实例理解nextTick的使用,并给出在页面渲染上的优化巧用

  (tips:代码的正确阅读方式:看template组成、跳过script代码、看代码后面的用例设计、看之后的代码分析、同时结合回头结合script代码理解)

<template>
<div>
<ul>
<li v-for="item in list1">{{item}}</li>
</ul>
<ul>
<li v-for="item in list2">{{item}}</li>
</ul>
<ol>
<li v-for="item in list3">{{item}}</li>
</ol>
<ol>
<li v-for="item in list4">{{item}}</li>
</ol>
<ol>
<li v-for="item in list5">{{item}}</li>
</ol>
</div>
</template>
<script type="text/javascript">
export default {
data() {
return {
list1: [],
list2: [],
list3: [],
list4: [],
list5: []
}
},
created() {
this.composeList12()
this.composeList34()
this.composeList5()
this.$nextTick(function() {
// DOM 更新了
console.log('finished test ' + new Date().toString())
console.log(document.querySelectorAll('li').length)
})
},
methods: {
composeList12() {
let me = this
let count = 10000 for (let i = 0; i < count; i++) {
Vue.set(me.list1, i, 'I am a 测试信息~~啦啦啦' + i)
}
console.log('finished list1 ' + new Date().toString()) for (let i = 0; i < count; i++) {
Vue.set(me.list2, i, 'I am a 测试信息~~啦啦啦' + i)
}
console.log('finished list2 ' + new Date().toString()) this.$nextTick(function() {
// DOM 更新了
console.log('finished tick1&2 ' + new Date().toString())
console.log(document.querySelectorAll('li').length)
})
},
composeList34() {
let me = this
let count = 10000 for (let i = 0; i < count; i++) {
Vue.set(me.list3, i, 'I am a 测试信息~~啦啦啦' + i)
}
console.log('finished list3 ' + new Date().toString()) this.$nextTick(function() {
// DOM 更新了
console.log('finished tick3 ' + new Date().toString())
console.log(document.querySelectorAll('li').length)
}) setTimeout(me.setTimeout1, 0)
},
setTimeout1() {
let me = this
let count = 10000 for (let i = 0; i < count; i++) {
Vue.set(me.list4, i, 'I am a 测试信息~~啦啦啦' + i)
}
console.log('finished list4 ' + new Date().toString()) me.$nextTick(function() {
// DOM 更新了
console.log('finished tick4 ' + new Date().toString())
console.log(document.querySelectorAll('li').length)
})
},
composeList5() {
let me = this
let count = 10000 this.$nextTick(function() {
// DOM 更新了
console.log('finished tick5-1 ' + new Date().toString())
console.log(document.querySelectorAll('li').length)
}) setTimeout(me.setTimeout2, 0)
},
setTimeout2() {
let me = this
let count = 10000 for (let i = 0; i < count; i++) {
Vue.set(me.list5, i, 'I am a 测试信息~~啦啦啦' + i)
}
console.log('finished list5 ' + new Date().toString()) me.$nextTick(function() {
// DOM 更新了
console.log('finished tick5 ' + new Date().toString())
console.log(document.querySelectorAll('li').length)
})
}
}
}
</script>

  2.1、用例设计
    用例1:通过list1、2、3验证,处在同步代码中的DOM更新情况及nextTick的触发时机;
    用例2:通过list3、list4验证,同步代码及异步代码中Dom更新及nextTick触发的区别;
    用例3:通过list4、list5对比验证,多个异步代码中nextTick触发的区别;
    用例4:通过在视图更新后获取DOM中<li>的数量,判断nextTick序列渲染的时间点。
 
  2.2、代码分析
    函数执行步骤:
      事件循环1:
        step1: this.composeList12() -> update list1, update list2 -> 绑定tick’1&2’
        step2: this.composeList34() -> update list3, 设置异步1setTimeout1 -> 绑定tick’3’
        step3: this.composeList5() -> 绑定tick’5-1’ -> 设置异步2setTimeout2 
        step4: 绑定tick’test’
      事件循环2:
        将setTimeout1的callback推入执行栈 -> update list4 -> 绑定tick’4’
      事件循环3:
        将setTimeout2的callback推入执行栈 -> update list5 -> 绑定tick’5’
 
  2.3、推断输出消息
    由于同一事件循环中的tick按执行顺序,因此消息输出为即:
      [同步环境]update list1 -> update list2 -> update list3 -> tick‘1&2’ -> tick‘3’ -> tick’5-1’ -> tick’test'
      [事件循环1]->update list4 -> tick’4’ 
       [事件循环2] ->update list5 -> tick’5’
 
  2.4、实际运行结果如下图
           
    该demo中,设置了5个size为10000的数组,从而能从时间及消息输出两个维度来了解nextTick的执行情况。另外,额外增加了一个参数,即更新后的视图中<li>的数量,从这个数量,可以考察出同一事件循环中的nextTick执行情况。由运行结果图可以看出实际的输出与推导的输出结果相符合。
 
  2.5、总结
    从用例1得出:
      a、在同一事件循环中,只有所有的数据更新完毕,才会调用nextTick;
      b、仅在同步执行环境数据完全更新完毕,DOM才开始渲染,页面才开始展现;
      c、在同一事件循环中,如果存在多个nextTick,将会按最初的执行顺序进行调用;
    从用例1+用例4得出:
      d、从同步执行环境中的四个tick对应的‘li’数量均为30000可看出,同一事件循环中,nextTick所在的视图是相同的;
    从用例2得出:
      e、只有同步环境执行完毕,DOM渲染完毕之后,才会处理异步callback
    从用例3得出:
      f、每个异步callback最后都会处在一个独立的事件循环中,对应自己独立的nextTick;
    从用例1结论中可得出:
      g、这个事件环境中的数据变化完成,在进行渲染[视图更新],可以避免DOM的频繁变动,从而避免了因此带来的浏览器卡顿,大幅度提升性能;
    从b可以得出:
      h、在首屏渲染、用户交互过程中,要巧用同步环境及异步环境;首屏展现的内容,尽量保证在同步环境中完成;其他内容,拆分到异步中,从而保证性能、体验。
    
  tips:
    1、可产生异步callback的有:promise(microtask queue)、setTimeout、MutationObserver、DOM事件、Ajax等;
    2、 vue DOM的视图更新实现,,使用到了ES6的Promise及HTML5的MutationObserver,当环境不支持时,使用setTimeout(fn, 0)替代。上述的三种方法,均为异步API。其中MutationObserver类似事件,又有所区别;事件是同步触发,其为异步触发,即DOM发生变化之后,不会立刻触发,等当前所有的DOM操作都结束后触发。关于异步API、事件循环将在以后补充。
 
    事件循环、任务队列详解:http://www.cnblogs.com/hity-tt/p/6733062.html
 

vue nextTick深入理解-vue性能优化、DOM更新时机、事件循环机制的更多相关文章

  1. js的事件循环机制:同步与异步任务(setTimeout,setInterval)宏任务,微任务(Promise,process.nextTick)

    javascript是单线程,一切javascript版的"多线程"都是用单线程模拟出来的,通过事件循环(event loop)实现的异步. javascript事件循环 事件循环 ...

  2. 对javascript EventLoop事件循环机制不一样的理解

    前置知识点: 浏览器原理,浏览器内核5种线程及协作,JS引擎单线程设计推荐阅读: 从浏览器多进程到JS单线程,JS运行机制最全面的一次梳理 [FE]浏览器渲染引擎「内核」 js异步编程,Promise ...

  3. 深入理解JavaScript事件循环机制

    前言 众所周知,JavaScript 是一门单线程语言,虽然在 html5 中提出了 Web-Worker ,但这并未改变 JavaScript 是单线程这一核心.可看HTML规范中的这段话: To ...

  4. 对vue nextTick深入理解-vue性能优化、DOM更新时机、事件循环机制

    一.定义[nextTick.事件循环] nextTick的由来: 由于VUE的数据驱动视图更新,是异步的,即修改数据的当下,视图不会立刻更新,而是等同一事件循环中的所有数据变化完成之后,再统一进行视图 ...

  5. vue nexttick的理解和使用场景

    应用场景 需要在视图更新之后,基于新的视图进行操作 文档说明 在下次 DOM 更新循环结束之后执行延迟回调.在修改数据之后立即使用这个方法,获取更新后的 DOM nextTick原理 1.异步说明 V ...

  6. JS性能优化——DOM编程

    浏览器中的DOM  天生就慢 DOM是个与语言无关的API,它在浏览器中的接口却是用JavaScript实现的.客户端脚本编程大多数时候是在个底层文档打交道,DOM就成为现在JavaScript编码中 ...

  7. Android性能优化之Listview(ViewHolder重用机制)

    相信大家在很多时候都会用到ListView这个控件,因为确实是用的很多很多,但是有木有遇到过当数据很多很多的时候,往下滑ListView时有时候会卡顿,这就需要我们来优化它了. ListView优化主 ...

  8. JavaScript性能优化 DOM编程

    最近在研读<高性能JavaScript>,在此做些简单记录.示例代码可在此处查看到. 一.DOM 1)DOM和JavaScript 文档对象模型(DOM)是一个独立于语言的,用于操作XML ...

  9. MySQL性能优化(七·上)-- 锁机制 之 表锁

    前言 数据库的锁主要用来保证数据的一致性的.MyISAM存储引擎只支持表锁,InnoDB存储引擎既支持行锁,也支持表锁,但默认情况下是采用行锁. 一.锁分类 1.按照对数据操作的类型分:读锁,写锁 读 ...

随机推荐

  1. C# 图书整理

    C#测试驱动开发C#设计模式C#高级编程单元测试之道C#版:使用Nunit 继续添加......

  2. go开源项目influxdb-relay源码分析(一)

    influxdb-relay项目地址: https://github.com/influxdata/influxdb-relay,主要作为负载均衡节点,写入多个influxdb节点,起到高可用效果. ...

  3. C# SQLite 数据库

    数据库 Oracle.Oracle的应用,主要在传统行业的数据化业务中,比如:银行.金融这样的对可用性.健壮性.安全性.实时性要求极高的业务 MS SQL Server.windows生态系统的产品, ...

  4. PDF文档转换为图片、图片转成PDF 及PDF合并

    简介 功能:PDF文档按每页转换成一张图片,一张图片转换成一张PDF 并将多张PDF合成一个多页的PDF文档. 经历:在各个网站上搜索始终出现各种问题,尤其是遇到引用的版本问题尤其头疼,不是不能适用当 ...

  5. ASP Session的功能的缺陷(进程外的Session)

    目前ASP的开发人员都正在使用Session这一强大的功能,但是在他们使用的过程中却发现了ASP Session有以下缺陷: 进程依赖性:ASP Session状态存于IIS的进程中,也就是ineti ...

  6. Winfrom PictureBox 设置图片自适应

    初始状态 Bitmap bm = new Bitmap(Image.FromStream(System.Net.WebRequest.Create(new Uri(result.Result)).Ge ...

  7. 知识记录——CSS规范(文章内容为转载)

    原作者信息 作者:词晖 链接:http://www.zhihu.com/question/19586885/answer/48933504 来源:知乎 著作权归原作者所有,转载请联系原作者获得授权. ...

  8. Android ScrollView 去掉 scrollbar 和 阴影

    1. 在 layout 里: android:scrollbars="none" android:overScrollMode="never" 2. 代码里 / ...

  9. 基于SSH的客户关系管理系统CRM-JavaWeb项目-有源码

    开发工具:Myeclipse/Eclipse + MySQL + Tomcat 项目简介: 项目的编译和运行:1 将数据库导入MysSql里 :打开HeidiSql这个图形化工具,新建一个数据库, 可 ...

  10. nginx实现动静分离--附nginx配置文件详解

    转自http://www.cnblogs.com/1214804270hacker/p/9299462.html 一.认识访问静态资源与访问动态资源的区别 静态资源:指存储在硬盘内的数据,固定的数据, ...