怎吗提升

vue的HTML模板到啦最后会被写进render(渲染函数)中
代码示例

  1. <template>
  2. <img alt="Vue logo" src="./assets/logo.png" />
  3. <HelloWorld msg="Hello Vue 3.0 + Vite" />
  4. </template>
  5. <script>
  6. import HelloWorld from './components/HelloWorld.vue'
  7. export default {
  8. name: 'App',
  9. components: {
  10. HelloWorld
  11. }
  12. }
  13. </script>

如图
image.png
蓝色框中是经过效率提升的,将一些不会改变的静态值提出来,
红色框中是渲染函数

静态提升

何为静态何为动态

静态: 在vue的HTML模板中,当不需要数据响应式,都是固定死的属性或文本都是静态的

  1. <template>
  2. <h1> I am title </h1>
  3. <h1 class="title"> I am title </h1>
  4. <img src="../assets/logo.png" alt="">
  5. </template>

动态:显示的文本或属性都是响应式数据的称之为动态

  1. <template>
  2. <h1>{{ msg }}</h1>
  3. <button @click="count++">count is: {{ count }}</button>
  4. </template>

静态节点提升

那些静态节点会被提升

  • 元素节点
  • 没有绑定动态内容 ```vue // vue2 的静态节点 render(){ createVNode(“h1”, null, “Hello World”) // … }

// vue3 的静态节点 const hoisted = createVNode(“h1”, null, “Hello World”) function render(){ // 直接使用 hoisted 即可 }

  1. <a name="Fp82B"></a>
  2. ### 静态属性提升
  3. ```vue
  4. <div class="user">
  5. {{user.name}}
  6. </div>
  1. const hoisted = { class: "user" }
  2. function render(){
  3. createVNode("div", hoisted, user.name)
  4. // ...
  5. }

预字符串化

预字符串话需要大量连续的静态节点才会触发,最少也要20个起步,如果不是大量连续的话还是会用vue2的方式

  1. <div class="menu-bar-container">
  2. <div class="logo">
  3. <h1>logo</h1>
  4. </div>
  5. <ul class="nav">
  6. <li><a href="">menu</a></li>
  7. <li><a href="">menu</a></li>
  8. <li><a href="">menu</a></li>
  9. <li><a href="">menu</a></li>
  10. <li><a href="">menu</a></li>
  11. </ul>
  12. <div class="user">
  13. <span>{{ user.name }}</span>
  14. </div>
  15. </div>

当编译器遇到大量连续的静态内容,会直接将其编译为一个普通字符串节点

  1. const _hoisted_2 = _createStaticVNode("<div class=\"logo\"><h1>logo</h1></div><ul class=\"nav\"><li><a href=\"\">menu</a></li><li><a href=\"\">menu</a></li><li><a href=\"\">menu</a></li><li><a href=\"\">menu</a></li><li><a href=\"\">menu</a></li></ul>")

vue2的渲染虚拟节点树的示意图,vue2会将所有的节点重新渲染
效率的提升 - 图2
vue3虚拟节点树 vue3会将重新渲染动态,静态节点不会再次渲染
效率的提升 - 图3

缓存事件处理函数

vue3对事件的缓存,vue3会认为触发这次事件而启动的事件函数,下次再触发事件不会换成一个新事件函数。故而将事件函数缓存起来

  1. <button @click="count++">plus</button>
  1. // vue2
  2. render(ctx){
  3. return createVNode("button", {
  4. onClick: function($event){
  5. ctx.count++;
  6. }
  7. })
  8. }
  9. // vue3 当事件有缓存会直接使用缓存好的事件,如果没有缓存事件将会给该缓存事件赋值
  10. render(ctx, _cache){
  11. return createVNode("button", {
  12. onClick: cache[0] || (cache[0] = ($event) => (ctx.count++))
  13. })
  14. }

虚拟dom树的比对

block Tree

vue2在对比新旧树的时候,并不知道哪些节点是静态的,哪些是动态的,因此只能一层一层比较,这就浪费了大部分时间在比对静态节点上
示例代码

  1. <form>
  2. <div>
  3. <label>账号:</label>
  4. <input v-model="user.loginId" />
  5. </div>
  6. <div>
  7. <label>密码:</label>
  8. <input v-model="user.loginPwd" />
  9. </div>
  10. </form>

vue2 的比对方式示意图 vue2会将所有节点节点进行对比
效率的提升 - 图4
vue3的比对方式示意图
效率的提升 - 图5上图中灰色的是静态节点,橙色的是动态,黑色是根节点
vue3 的虚拟dom树对比,根节点下会有一个装有所有动态节点的数组,每个根节点下都是一个块也就是一个区域,这样会跳过静态节点

PathFlag

vue3 会觉得对比某一节点还是会浪费效率,因为不知道该节点改变啦啥,就需要对该节点比对内容,属性,PathFlag会记录该动态节点哪一点是动态的

当我们修改为动态内容

示例代码

  1. <template>
  2. <h1>{{ msg }}</h1>
  3. <img alt="Vue logo" src="./assets/logo.png" />
  4. <HelloWorld msg="Hello Vue 3.0 + Vite" />
  5. </template>
  6. <script>
  7. import HelloWorld from './components/HelloWorld.vue'
  8. export default {
  9. name: 'App',
  10. components: {
  11. HelloWorld
  12. },
  13. data() {
  14. return {
  15. msg: "我是动态内容"
  16. }
  17. }
  18. }
  19. </script>

h1元素是动态内容,当我们查看浏览器中编译好文件:
image.png
图中显示的代码

  1. import {toDisplayString as _toDisplayString, createVNode as _createVNode, resolveComponent as _resolveComponent, Fragment as _Fragment, openBlock as _openBlock, createBlock as _createBlock} from "/@modules/vue.js"
  2. const _hoisted_1 = /*#__PURE__*/
  3. _createVNode("img", {
  4. alt: "Vue logo",
  5. src: "/src/assets/logo.png"
  6. }, null, -1 /* HOISTED */
  7. )
  8. export function render(_ctx, _cache, $props, $setup, $data, $options) {
  9. const _component_HelloWorld = _resolveComponent("HelloWorld")
  10. return (_openBlock(),
  11. _createBlock(_Fragment, null, [_createVNode("h1", null, _toDisplayString($data.msg), 1 /* TEXT */
  12. ), _hoisted_1, _createVNode(_component_HelloWorld, {
  13. msg: "Hello Vue 3.0 + Vite"
  14. })], 64 /* STABLE_FRAGMENT */
  15. ))
  16. }
  17. //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIkU6XFzns7vnu5/pu5jorqRcXOahjOmdolxcdml0ZVxc5pWI546H5o+Q5Y2HXFx4aWFvbHZcXHNyY1xcQXBwLnZ1ZSJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztnQ0FFRSxhQUE4QztFQUF6QyxHQUFHLEVBQUMsVUFBVTtFQUFDLEdBQUcsRUFBQyxzQkFBbUI7Ozs7Ozs7SUFEM0MsYUFBa0IsNkJBQVgsU0FBRztJQUNWLFVBQThDO0lBQzlDLGFBQXlDLHlCQUE3QixHQUFHLEVBQUMsc0JBQXNCIiwiZmlsZSI6IkU6L+ezu+e7n+m7mOiupC/moYzpnaIvdml0ZS/mlYjnjofmj5DljYcveGlhb2x2L3NyYy9BcHAudnVlIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXNDb250ZW50IjpbIjx0ZW1wbGF0ZT5cbiAgPGgxPnt7IG1zZyB9fTwvaDE+XG4gIDxpbWcgYWx0PVwiVnVlIGxvZ29cIiBzcmM9XCIuL2Fzc2V0cy9sb2dvLnBuZ1wiIC8+XG4gIDxIZWxsb1dvcmxkIG1zZz1cIkhlbGxvIFZ1ZSAzLjAgKyBWaXRlXCIgLz5cbjwvdGVtcGxhdGU+XG5cbjxzY3JpcHQ+XG5pbXBvcnQgSGVsbG9Xb3JsZCBmcm9tICcuL2NvbXBvbmVudHMvSGVsbG9Xb3JsZC52dWUnXG5cbmV4cG9ydCBkZWZhdWx0IHtcbiAgbmFtZTogJ0FwcCcsXG4gIGNvbXBvbmVudHM6IHtcbiAgICBIZWxsb1dvcmxkXG4gIH0sXG4gIGRhdGEoKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIG1zZzogXCLmiJHmmK/liqjmgIHlhoXlrrlcIlxuICAgIH1cbiAgfVxufVxuPC9zY3JpcHQ+XG4iXX0=

如上图你会发现h1元素在渲染函数中打上啦标签 也就是 1 /* TEXT */ 这个标签就说明这动态节点的内容是动态的

当我们修改为动态类名

示例代码

  1. <template>
  2. <h1 :class="msg">{{ msg }}</h1>
  3. <img alt="Vue logo" src="./assets/logo.png" />
  4. <HelloWorld msg="Hello Vue 3.0 + Vite" />
  5. </template>
  6. <script>
  7. import HelloWorld from './components/HelloWorld.vue'
  8. export default {
  9. name: 'App',
  10. components: {
  11. HelloWorld
  12. },
  13. data() {
  14. return {
  15. msg: "我是动态内容"
  16. }
  17. }
  18. }
  19. </script>

浏览里编译好的代码为:
image.png
图中显示的代码为

  1. import {toDisplayString as _toDisplayString, createVNode as _createVNode, resolveComponent as _resolveComponent, Fragment as _Fragment, openBlock as _openBlock, createBlock as _createBlock} from "/@modules/vue.js"
  2. const _hoisted_1 = /*#__PURE__*/
  3. _createVNode("img", {
  4. alt: "Vue logo",
  5. src: "/src/assets/logo.png"
  6. }, null, -1 /* HOISTED */
  7. )
  8. export function render(_ctx, _cache) {
  9. const _component_HelloWorld = _resolveComponent("HelloWorld")
  10. return (_openBlock(),
  11. _createBlock(_Fragment, null, [_createVNode("h1", {
  12. class: _ctx.msg
  13. }, _toDisplayString(_ctx.msg), 3 /* TEXT, CLASS */
  14. ), _hoisted_1, _createVNode(_component_HelloWorld, {
  15. msg: "Hello Vue 3.0 + Vite"
  16. })], 64 /* STABLE_FRAGMENT */
  17. ))
  18. }
  19. //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIkU6XFzns7vnu5/pu5jorqRcXOahjOmdolxcdml0ZVxc5pWI546H5o+Q5Y2HXFx4aWFvbHZcXHNyY1xcQXBwLnZ1ZSJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztnQ0FFRSxhQUE4QztFQUF6QyxHQUFHLEVBQUMsVUFBVTtFQUFDLEdBQUcsRUFBQyxzQkFBbUI7Ozs7Ozs7SUFEM0MsYUFBK0IsUUFBMUIsS0FBSyxFQUFFLFFBQUcscUJBQUssUUFBRztJQUN2QixVQUE4QztJQUM5QyxhQUF5Qyx5QkFBN0IsR0FBRyxFQUFDLHNCQUFzQiIsImZpbGUiOiJFOi/ns7vnu5/pu5jorqQv5qGM6Z2iL3ZpdGUv5pWI546H5o+Q5Y2HL3hpYW9sdi9zcmMvQXBwLnZ1ZSIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyI8dGVtcGxhdGU+XG4gIDxoMSA6Y2xhc3M9XCJtc2dcIj57eyBtc2cgfX08L2gxPlxuICA8aW1nIGFsdD1cIlZ1ZSBsb2dvXCIgc3JjPVwiLi9hc3NldHMvbG9nby5wbmdcIiAvPlxuICA8SGVsbG9Xb3JsZCBtc2c9XCJIZWxsbyBWdWUgMy4wICsgVml0ZVwiIC8+XG48L3RlbXBsYXRlPlxuXG48c2NyaXB0PlxuaW1wb3J0IEhlbGxvV29ybGQgZnJvbSAnLi9jb21wb25lbnRzL0hlbGxvV29ybGQudnVlJ1xuXG5leHBvcnQgZGVmYXVsdCB7XG4gIG5hbWU6ICdBcHAnLFxuICBjb21wb25lbnRzOiB7XG4gICAgSGVsbG9Xb3JsZFxuICB9LFxuICBkYXRhKCkge1xuICAgIHJldHVybiB7XG4gICAgICBtc2c6IFwi5oiR5piv5Yqo5oCB5YaF5a65XCJcbiAgICB9XG4gIH1cbn1cbjwvc2NyaXB0PlxuIl19

从上图我画蓝框中显示的内容为3 /* TEXT, CLASS */ 可以看出class为2 后面的内容就提示出啦该节点的内容与类名是动态的

当是动态属性为

示例代码

  1. <template>
  2. <h1 :title="msg">h1</h1>
  3. <img :alt=" msg" src="./assets/logo.png" />
  4. <HelloWorld msg="Hello Vue 3.0 + Vite" />
  5. </template>
  6. <script>
  7. import HelloWorld from './components/HelloWorld.vue'
  8. export default {
  9. name: 'App',
  10. components: {
  11. HelloWorld
  12. },
  13. data() {
  14. return {
  15. msg: "我是动态内容"
  16. }
  17. }
  18. }
  19. </script>

image.png
图中显示的代码为

  1. import {createVNode as _createVNode, resolveComponent as _resolveComponent, Fragment as _Fragment, openBlock as _openBlock, createBlock as _createBlock} from "/@modules/vue.js"
  2. export function render(_ctx, _cache) {
  3. const _component_HelloWorld = _resolveComponent("HelloWorld")
  4. return (_openBlock(),
  5. _createBlock(_Fragment, null, [_createVNode("h1", {
  6. title: _ctx.msg
  7. }, "h1", 8 /* PROPS */
  8. , ["title"]), _createVNode("img", {
  9. alt: _ctx.msg,
  10. src: "/src/assets/logo.png"
  11. }, null, c
  12. , ["alt"]), _createVNode(_component_HelloWorld, {
  13. msg: "Hello Vue 3.0 + Vite"
  14. })], 64 /* STABLE_FRAGMENT */
  15. ))
  16. }
  17. //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIkU6XFzns7vnu5/pu5jorqRcXOahjOmdolxcdml0ZVxc5pWI546H5o+Q5Y2HXFx4aWFvbHZcXHNyY1xcQXBwLnZ1ZSJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7SUFDRSxhQUF3QixRQUFuQixLQUFLLEVBQUUsUUFBRyxJQUFFLElBQUU7SUFDbkIsYUFBMkM7TUFBckMsR0FBRyxHQUFHLFFBQUc7TUFBRSxHQUFHLEVBQUMsc0JBQW1COztJQUN4QyxhQUF5Qyx5QkFBN0IsR0FBRyxFQUFDLHNCQUFzQiIsImZpbGUiOiJFOi/ns7vnu5/pu5jorqQv5qGM6Z2iL3ZpdGUv5pWI546H5o+Q5Y2HL3hpYW9sdi9zcmMvQXBwLnZ1ZSIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyI8dGVtcGxhdGU+XG4gIDxoMSA6dGl0bGU9XCJtc2dcIj5oMTwvaDE+XG4gIDxpbWcgOmFsdD1cIiBtc2dcIiBzcmM9XCIuL2Fzc2V0cy9sb2dvLnBuZ1wiIC8+XG4gIDxIZWxsb1dvcmxkIG1zZz1cIkhlbGxvIFZ1ZSAzLjAgKyBWaXRlXCIgLz5cbjwvdGVtcGxhdGU+XG5cbjxzY3JpcHQ+XG5pbXBvcnQgSGVsbG9Xb3JsZCBmcm9tICcuL2NvbXBvbmVudHMvSGVsbG9Xb3JsZC52dWUnXG5cbmV4cG9ydCBkZWZhdWx0IHtcbiAgbmFtZTogJ0FwcCcsXG4gIGNvbXBvbmVudHM6IHtcbiAgICBIZWxsb1dvcmxkXG4gIH0sXG4gIGRhdGEoKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIG1zZzogXCLmiJHmmK/liqjmgIHlhoXlrrlcIlxuICAgIH1cbiAgfVxufVxuPC9zY3JpcHQ+XG4iXX0=

你会发现动态属性为 "h1", 8 /* PROPS */