当前位置: 首页 > news >正文

vue深入理解(1)

本文章内容主要来源于《vue.js设计与实现》

视图层框架设计

命令式和声明式

范式上,视图层框架通常分为命令式和范式

JQuery就是典型的命令式框架,命令式框架的一大特点就是关注过程

例子:

$('#app') // 获取app.text('hello world') // 设置文本内容.on('click', () => { alert('ok') })

原生JS实现例子:

const div = document.querySelector('#app')
div.innerText = 'hello world'
div.addEventListener('click', () => { alert('ok') })

声明式框架更加关注结果

vue.js例子:

<div @click="() => alert('ok')">hello world
</div>

可以看出在vue.js实现就是提供的是一个“结果”,怎么去实现的这个过程我们并不关心这是由vue.js帮我们完成的

也就是Vue封装了这个过程

  • vue的内部实现一定是命令式的,而暴露给用户的则更加声明式

两者性能与可维护性比较

命令式代码的性能优于声明式的性能

若要实现修改文本内容如上面代码,只需要直接调用相关命令即可

div.innerText = 'nihao'

理论上命令式代码可以做到极致的代码优化(因为明确知道哪些发生更改,只需要做必要的修改

对于框架而言,为了实现最优的更新性能,需要找到前后差异并只更新变化的地方

把直接修改消耗的性能定义为A,把找出差异的性能消耗定义为B

  • 命令式代码的更新性能消耗=A
  • 声明式代码的更新性能消耗=B + A

声明式代码的可维护性更强(命令式代码需要维护实现目标的整个过程)

虚拟DOM性能

该部分主要是初步介绍虚拟DOM,主要讲述为什么选择虚拟DOM

由于声明式代码的更新性能消耗=B + A

为了最小化找出差异的性能消耗,所以让声明式代码的性能无限接近于命令式消耗 -------- 虚拟DOM就是为了最小化找出差异这一步的性能消耗

理论上采用虚拟DOM的更新技术的性能不可能比原生JS操作DOM更高

虚拟DOM在vue中使用就是为了写声明式代码,还能够保证应用程序的性能下限

以上说的原生JS指的是类似于document.creatElement之类的DOM操作,并不包含innerHTML

innerHTML操作页面

使用innerHTML创建页面需要构建一段HTML字符串,然后将字符串赋值给DOM元素的innerHTML属性

  • 但深层并非这句话这么简单,为了渲染出页面,首先要把字符串解析成DOM树(这是一个DOM层面的计算

涉及DOM的计算要远比JS层面的计算性能差,纯JS层面的操作比DOM操作快得多,甚至不在一个数量级

请添加图片描述

使用innerHTML更新页面的过程是重新构建HTML字符串,再重新设置DOM元素的innerHTML属性(相当于销毁所有旧的DOM元素,再 全量 创建新的DOM元素

虚拟DOM操作页面

使用虚拟DOM创建页面首先创建JS对象(该对象为真实DOM的映照),然后递归地遍历DOM树并创建真实DOM

使用虚拟DOM更新页面需要重新创建虚拟DOM树,然后比较新旧虚拟DOM,找到变化地元素并更新它

两者相比

虚拟DOM在 JS层面的计算 要比创建页面是多出一个Diff的性能消耗,但不会产生数量级的差异 ;然后DOM层面的计算,虚拟DOM在更新页面时只会更新必要的元素,但innerHTML要全量更新

性能总结

请添加图片描述

运行时、编译时

编译时(Compile Time)和运行时(Runtime)指的是程序在不同的阶段进行的不同类型的处理。

js 编译是什么呢?
现代前端开发,我们都是使用 react、vue、webpack 等工具,其实就是把这些框架代码编译成了 js 代码,那么编译时其实是指的,webpack 等工具把 react、vue 编译为 js 的过程。运行时自然不用说,就是浏览器解释 js 代码的过程。

纯运行时框架例子

// 渲染 dom
function render (node, root) {const el = document.createElement(node.tag)if (typeof node.children === 'string') {const text = document.createTextNode(node.children)el.appendChild(text)}if (Array.isArray(node.children)) {node.children.forEach(child => render(child, el)) // 递归地处理节点的渲染}root.appendChild(el)
}const node = {tag: 'div', // tag代表标签名称children: [ // children可以是一个数组,代表子节点{tag: 'h1',children: 'hello' // children也可以是一段文本,代表文本子节点}]
}render(node, document.body)

用户在使用render函数渲染内容时,直接为render函数提供了一个树型结构的数据对象

但若是用户需求是手写树型结构的数据对象太麻烦了,而且不直观,想要支持用类似HTML的方式描述树型结构的数据对象,所以引入编译的手段,把HTML标签编译成树型结构的数据对象

纯编译时框架例子

<div><h1>hello</h1>
</div>

经过编译

const div = document.createElement('div')
const h1 = document.createElement('h1')
h1.innerText = 'hello'
div.appendChild(h1)
document.body.appendChild(div)

直接将HTML字符串编译成命令式代码过程

编译时+运行时框架例子

编写一个Compiler的程序,作用是把HTML字符串编译成树型结构的数据对象

const html = '
<div><span>hello</span>
</div>
'
// 调用Compiler编译得到树形结构的数据对象
const obj = Compiler(html)
// 再调用render进行渲染
render(obj, document.bod)

http://www.mrgr.cn/news/79535.html

相关文章:

  • 不使用cmake进行CloudCompare插件开发
  • 去除背景 学习笔记
  • Python 单例模式工厂模式和classmethod装饰器
  • 2024美赛数学建模C题:网球比赛中的动量,用马尔可夫链求解!详细分析
  • JavaWeb学习--cookie和session,实现登录的记住我和验证码功能
  • 在 Ansys Q3D 中求解直流和交流电感
  • MySQL数据库(3)-SQL基础语言学习
  • 《MySQL 表结构设计基础》
  • IdentityServer4框架、ASP.NET core Identity
  • 【Redis】not support: redis
  • 《MySQL 入门:数据库世界的第一扇门》
  • HTML旋转爱心(完整代码)
  • Qt学习笔记第51到60讲
  • 39 vector深入理解 · 迭代器失效深度浅拷贝
  • 【人工智能基础06】人工神经网络基础(二):1. 权值初始化(权值优化、避免梯度爆炸、消失)、2. 权值衰减(防止过拟合)与 3. 权值共享(卷积核)
  • spring boot验证码
  • Kafka服务器的简单部署以及消息的生产、消费、监控
  • 【CKS最新模拟真题】获取多个集群的上下文名称并保存到指定文件中
  • Unity教程(十九)战斗系统 受击反馈
  • 避大坑!Vue3中reactive丢失响应式的问题
  • 链表OJ题型讲解与总结
  • 力扣每日一题 - 999. 可以被一步捕获的棋子数
  • 默认插槽,具名插槽(v-slot:具名,name=‘ ‘),作用域插槽
  • Ubuntu Linux 图形界面工具管理磁盘分区和文件系统(八)
  • 电子商务人工智能指南 1/6 - 搜索、广告和发现
  • 1-1 C语言链表