百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分类 > 正文

尤大大教你Vue3.0虚拟Dom快速入门【实践】

ztj100 2024-11-02 14:31 18 浏览 0 评论

作者:蜗牛老湿

转发链接:https://juejin.im/post/5e9faa8fe51d4546fe263eda

整体尤大直播的过程,劝退大兄弟已经总结的贼棒了 ,请访问:

聊聊昨晚尤雨溪现场针对Vue3.0 Beta版本新特性知识点汇总

Vue3核心的Typescript,Proxy响应式,Composition解决代码反复横跳都有很棒的文章剖析了, 我总结一下虚拟Dom部分把,并对比一下React, vdom的重写也是vue3性能如此优秀的重要原因

  1. Vue真是太好了 壹万多字的Vue知识点 超详细!
  2. Vue 3.0 Beta 和React 开发者分别杠上了

Vue3.0的虚拟dom

先说结论,静态标记,upadte性能提升1.3~2倍,ssr提升2~3倍,怎么做到的呢




编译模板的静态标记

我们来看一段很常见的代码

<div id="app">
    <h1>技术摸鱼</h1>
    <p>今天天气真不错</p>
    <div>{{name}}</div>

</div>

复制代码

vue2中会解析

function render() {
  with(this) {
    return _c('div', {
      attrs: {
        "id": "app"
      }
    }, [_c('h1', [_v("技术摸鱼")]), _c('p', [_v("今天天气真不错")]), _c('div', [_v(
      _s(name))])])
  }
}

复制代码

其中前面两个标签是完全静态的,后续的渲染中不会产生任何变化,Vue2中依然使用_c新建成vdom,在diff的时候需要对比,有一些额外的性能损耗

我们看下vue3中的解析结果

import { createVNode as _createVNode, toDisplayString as _toDisplayString, openBlock as _openBlock, createBlock as _createBlock } from "vue"

export function render(_ctx, _cache) {
  return (_openBlock(), _createBlock("div", { id: "app" }, [
    _createVNode("h1", null, "技术摸鱼"),
    _createVNode("p", null, "今天天气真不错"),
    _createVNode("div", null, _toDisplayString(_ctx.name), 1 /* TEXT */)
  ]))
}
// Check the console for the AST

复制代码



最后一个_createVNode第四个参数1,只有带这个参数的,才会被真正的追踪,静态节点不需要遍历,这个就是vue3优秀性能的主要来源,再看复杂一点的

<div id="app">
    <h1>技术摸鱼</h1>
    <p>今天天气真不错</p>

    <div>{{name}}</div>
    <div :class="{red:isRed}">摸鱼符</div>
    <button @click="handleClick">戳我</button>
    <input type="text" v-model="name">
    
</div>

复制代码

解析的结果 在线预览


import { createVNode as _createVNode, toDisplayString as _toDisplayString, openBlock as _openBlock, createBlock as _createBlock } from "vue"

export function render(_ctx, _cache) {
  return (_openBlock(), _createBlock("div", { id: "app" }, [
    _createVNode("h1", null, "技术摸鱼"),
    _createVNode("p", null, "今天天气真不错"),
    _createVNode("div", null, _toDisplayString(_ctx.name), 1 /* TEXT */),
    _createVNode("div", {
      class: {red:_ctx.isRed}
    }, "摸鱼符", 2 /* CLASS */),
    _createVNode("button", { onClick: _ctx.handleClick }, "戳我", 8 /* PROPS */, ["onClick"])
  ]))
}

// Check the console for the AST

复制代码

_createVNode出第四个参数出现了别的数字,根据后面注释也很容易猜出,根据text,props等不同的标记,这样再diff的时候,只需要对比text或者props,不用再做无畏的props遍历, 优秀! 借鉴一下劝退大兄弟的注释

export const enum PatchFlags {
  
  TEXT = 1,// 表示具有动态textContent的元素
  CLASS = 1 << 1,  // 表示有动态Class的元素
  STYLE = 1 << 2,  // 表示动态样式(静态如style="color: red",也会提升至动态)
  PROPS = 1 << 3,  // 表示具有非类/样式动态道具的元素。
  FULL_PROPS = 1 << 4,  // 表示带有动态键的道具的元素,与上面三种相斥
  HYDRATE_EVENTS = 1 << 5,  // 表示带有事件监听器的元素
  STABLE_FRAGMENT = 1 << 6,   // 表示其子顺序不变的片段(没懂)。 
  KEYED_FRAGMENT = 1 << 7, // 表示带有键控或部分键控子元素的片段。
  UNKEYED_FRAGMENT = 1 << 8, // 表示带有无key绑定的片段
  NEED_PATCH = 1 << 9,   // 表示只需要非属性补丁的元素,例如ref或hooks
  DYNAMIC_SLOTS = 1 << 10,  // 表示具有动态插槽的元素
}
复制代码

如果同时有props和text的绑定呢, 位运算组合即可


<div id="app">
    <h1>技术摸鱼</h1>
    <p>今天天气真不错</p>
    <div :id="userid"">{{name}}</div>
</div>


复制代码
import { createVNode as _createVNode, toDisplayString as _toDisplayString, openBlock as _openBlock, createBlock as _createBlock } from "vue"

export function render(_ctx, _cache) {
  return (_openBlock(), _createBlock("div", { id: "app" }, [
    _createVNode("h1", null, "技术摸鱼"),
    _createVNode("p", null, "今天天气真不错"),
    _createVNode("div", {
      id: _ctx.userid,
      "\"": ""
    }, _toDisplayString(_ctx.name), 9 /* TEXT, PROPS */, ["id"])
  ]))
}

// Check the console for the AST

复制代码

text是1,props是8,组合在一起就是9,我们可以简单的通过位运算来判定需要做text和props的判断, 按位与即可,只要不是0就是需要比较



位运算来做类型组合 本身就是一个最佳实践,react大兄弟也是一样的 代码


export const PLUGIN_EVENT_SYSTEM = 1;
export const RESPONDER_EVENT_SYSTEM = 1 << 1;
export const USE_EVENT_SYSTEM = 1 << 2;
export const IS_TARGET_PHASE_ONLY = 1 << 3;
export const IS_PASSIVE = 1 << 4;
export const PASSIVE_NOT_SUPPORTED = 1 << 5;
export const IS_REPLAYED = 1 << 6;
export const IS_FIRST_ANCESTOR = 1 << 7;
export const LEGACY_FB_SUPPORT = 1 << 8;

复制代码

事件缓存

绑定的@click会存在缓存里 链接

<div id="app">
  <button @click="handleClick">戳我</button>
</div>

复制代码

export function render(_ctx, _cache) {
  return (_openBlock(), _createBlock("div", { id: "app" }, [
    _createVNode("button", {
      onClick: _cache[1] || (_cache[1] = $event => (_ctx.handleClick($event)))
    }, "戳我")
  ]))
}

复制代码

传入的事件会自动生成并缓存一个内联函数再cache里,变为一个静态节点。这样就算我们自己写内联函数,也不会导致多余的重复渲染 真是优秀啊

静态提升

代码

<div id="app">
    <h1>技术摸鱼</h1>
    <p>今天天气真不错</p>
    <div>{{name}}</div>
    <div :class="{red:isRed}">摸鱼符</div>
</div>

复制代码
const _hoisted_1 = { id: "app" }
const _hoisted_2 = _createVNode("h1", null, "技术摸鱼", -1 /* HOISTED */)
const _hoisted_3 = _createVNode("p", null, "今天天气真不错", -1 /* HOISTED */)

export function render(_ctx, _cache) {
  return (_openBlock(), _createBlock("div", _hoisted_1, [
    _hoisted_2,
    _hoisted_3,
    _createVNode("div", null, _toDisplayString(_ctx.name), 1 /* TEXT */),
    _createVNode("div", {
      class: {red:_ctx.isRed}
    }, "摸鱼符", 2 /* CLASS */)
  ]))
}

复制代码

vue3和react fiber的vdom

很多人吐槽越来越像React,其实越来越像的api,代表着前端的两个方向

Vue1.x

没有vdom,完全的响应式,每个数据变化,都通过响应式通知机制来新建Watcher干活,就像独立团规模小的时候,每个战士入伍和升职,都主动通知咱老李,管理方便

项目规模变大后,过多的Watcher,会导致性能的瓶颈





React15x

而React15时代,没有响应式,数据变了,整个新数据和老的数据做diff,算出差异 就知道怎么去修改dom了,就像老李指挥室有一个模型,每次人事变更,通过对比所有人前后差异,就知道了变化, 看起来有很多计算量,但是这种immutable的数据结构对大型项目比较友好,而且Vdom抽象成功后,换成别的平台render成为了可能,无论是打鬼子还是打国军,都用一个vdom模式

碰到的问题一样,如果dom节点持续变多,每次diff的时间超过了16ms,就可能会造成卡顿(60fps)



Vue2.x

引入vdom,控制了颗粒度,组件层面走watcher通知, 组件内部走vdom做diff,既不会有太多watcher,也不会让vdom的规模过大,diff超过16ms,真是优秀啊 就像独立团大了以后,只有营长排长级别的变动,才会通知老李,内部的自己diff管理了



React 16 Fiber

React走了另外一条路,既然主要问题是diff导致卡顿,于是React走了类似cpu调度的逻辑,把vdom这棵树,微观变成了链表,利用浏览器的空闲时间来做diff,如果超过了16ms,有动画或者用户交互的任务,就把主进程控制权还给浏览器,等空闲了继续,特别像等待女神的备胎



diff的逻辑,变成了单向的链表,任何时候主线程女神有空了,我们在继续蹭上去接盘做diff,大家研究下requestIdleCallback就知道,从浏览器角度看 是这样的



大概代码

requestIdelCallback(myNonEssentialWork);
// 等待女神空闲
function myNonEssentialWork (deadline) {
    // deadline.timeRemaining()>0 主线程女神还有事件
    // 还有diff任务没算玩
    while (deadline.timeRemaining() > 0 && tasks.length > 0) {
    doWorkIfNeeded();
    }
    // 女神没时间了,把女神还回去
    if (tasks.length > 0){
        requestIdleCallback(myNonEssentialWork);
    }
}

复制代码

Vue3

这里的静态提升和事件缓存刚才说过了,就不说了,其实我也很纳闷,这些静态标记和事件缓存,React本身也可以做,为啥就不实现了,连shouldComponentUpdate都得自己定义,为啥不把默认的组件都变成pure或者memo呢,唉,也许这就是人生把

React给你自由,Vue让你持久,可能也是现在国内Vue和React都如此受欢迎的原因把

Vue3通过Proxy响应式+组件内部vdom+静态标记,把任务颗粒度控制的足够细致,所以也不太需要time-slice了

人生啊,小孩才天天研究利弊, 成年人选择我都要,也期待React17的新特性



直播小细节

最后提问期间,强如尤大,也没法回避发量的问题,可惜没推荐啥护发素,我仔细看了一下,好像vue3发布后,尤大发际线确实提升了 囧 祝大家技术提升的同时也能有乌黑的秀发


作者:蜗牛老湿
转发链接:https://juejin.im/post/5e9faa8fe51d4546fe263eda

相关推荐

30天学会Python编程:16. Python常用标准库使用教程

16.1collections模块16.1.1高级数据结构16.1.2示例...

强烈推荐!Python 这个宝藏库 re 正则匹配

Python的re模块(RegularExpression正则表达式)提供各种正则表达式的匹配操作。...

Python爬虫中正则表达式的用法,只讲如何应用,不讲原理

Python爬虫:正则的用法(非原理)。大家好,这节课给大家讲正则的实际用法,不讲原理,通俗易懂的讲如何用正则抓取内容。·导入re库,这里是需要从html这段字符串中提取出中间的那几个文字。实例一个对...

Python数据分析实战-正则提取文本的URL网址和邮箱(源码和效果)

实现功能:Python数据分析实战-利用正则表达式提取文本中的URL网址和邮箱...

python爬虫教程之爬取当当网 Top 500 本五星好评书籍

我们使用requests和re来写一个爬虫作为一个爱看书的你(说的跟真的似的)怎么能发现好书呢?所以我们爬取当当网的前500本好五星评书籍怎么样?ok接下来就是学习python的正确姿...

深入理解re模块:Python中的正则表达式神器解析

在Python中,"re"是一个强大的模块,用于处理正则表达式(regularexpressions)。正则表达式是一种强大的文本模式匹配工具,用于在字符串中查找、替换或提取特定模式...

如何使用正则表达式和 Python 匹配不以模式开头的字符串

需要在Python中使用正则表达式来匹配不以给定模式开头的字符串吗?如果是这样,你可以使用下面的语法来查找所有的字符串,除了那些不以https开始的字符串。r"^(?!https).*&...

先Mark后用!8分钟读懂 Python 性能优化

从本文总结了Python开发时,遇到的性能优化问题的定位和解决。概述:性能优化的原则——优化需要优化的部分。性能优化的一般步骤:首先,让你的程序跑起来结果一切正常。然后,运行这个结果正常的代码,看看它...

Python“三步”即可爬取,毋庸置疑

声明:本实例仅供学习,切忌遵守robots协议,请不要使用多线程等方式频繁访问网站。#第一步导入模块importreimportrequests#第二步获取你想爬取的网页地址,发送请求,获取网页内...

简单学Python——re库(正则表达式)2(split、findall、和sub)

1、split():分割字符串,返回列表语法:re.split('分隔符','目标字符串')例如:importrere.split(',','...

Lavazza拉瓦萨再度牵手上海大师赛

阅读此文前,麻烦您点击一下“关注”,方便您进行讨论和分享。Lavazza拉瓦萨再度牵手上海大师赛标题:2024上海大师赛:网球与咖啡的浪漫邂逅在2024年的上海劳力士大师赛上,拉瓦萨咖啡再次成为官...

ArkUI-X构建Android平台AAR及使用

本教程主要讲述如何利用ArkUI-XSDK完成AndroidAAR开发,实现基于ArkTS的声明式开发范式在android平台显示。包括:1.跨平台Library工程开发介绍...

Deepseek写歌详细教程(怎样用deepseek写歌功能)

以下为结合DeepSeek及相关工具实现AI写歌的详细教程,涵盖作词、作曲、演唱全流程:一、核心流程三步法1.AI生成歌词-打开DeepSeek(网页/APP/API),使用结构化提示词生成歌词:...

“AI说唱解说影视”走红,“零基础入行”靠谱吗?本报记者实测

“手里翻找冻鱼,精心的布局;老漠却不言语,脸上带笑意……”《狂飙》剧情被写成歌词,再配上“科目三”背景音乐的演唱,这段1分钟30秒的视频受到了无数网友的点赞。最近一段时间随着AI技术的发展,说唱解说影...

AI音乐制作神器揭秘!3款工具让你秒变高手

在音乐创作的领域里,每个人都有一颗想要成为大师的心。但是面对复杂的乐理知识和繁复的制作过程,许多人的热情被一点点消磨。...

取消回复欢迎 发表评论: