Vue3源码reactivity响应式篇之批量更新

发布于:2025-09-11 ⋅ 阅读:(13) ⋅ 点赞:(0)

概述

在vue3响应式系统设计中,批量更新是优化性能的核心机制之一。当短时间内频繁多次修改响应式数据时,批量更新可以避免频繁触发订阅者的更新操作,将这些更新操作合并为一次,从而减少不必要的计算和DOM操作。

批量更新也是利用链表的方式实现。

批量更新的实现

核心变量

批量更新的实现依赖于3个核心变量:batchDepthbatchedSubbatchedComputed

let batchDepth = 0; // 批量更新的嵌套深度
let batchedSub;// 存储待执行的普通订阅者队列
let batchedComputed; // 存储待执行的计算属性computed订阅者队列(单独处理,有优先级)

核心方法

批量更新的实现依赖于3个核心方法:startBatchendBatchbatch

batch

batch方法的作用是将订阅者sub加入批量队列中。sub通常是ReactiveEffect实例,该方法不会立即执行更新,只是暂存将sub加入批量队列中,等待endBatch方法调用时统一执行。

batch方法的实现如下:

function batch(sub, isComputed = false) {
  // 标记订阅者为 EffectFlags.NOTIFIED "已加入批量队列"  
  sub.flags |= 8;
  if (isComputed) {
    // 若为计算属性订阅者,则加入计算属性链表中(单独维护)
    sub.next = batchedComputed; // 新订阅者放在链表的头部
    batchedComputed = sub;
    return;
  }
  // 若为普通订阅者,则加入普通订阅者链表中
  sub.next = batchedSub;
  batchedSub = sub;
}
startBatch

startBatch方法的作用是开启批量更新,将batchDepth1,说明后续的更新操作会被暂存,不立即执行。

function startBatch() {
  batchDepth++;
}
endBatch

endBatch就是当所有嵌套的批量更新都结束后(batchDepth减为0),执行链表中所有暂存的订阅者更新,并清理状态。

endBatch的源码实现如下:

function endBatch() {
  // 若批量更新仍有嵌套(深度未到0),不执行实际更新   
  if (--batchDepth > 0) {
    return;
  }
  // 处理计算属性订阅者链表
  if (batchedComputed) {
    let e = batchedComputed;
    batchedComputed = void 0; // 清空队列
    while (e) {
      const next = e.next;
      e.next = void 0;// 重置链表指针
      e.flags &= -9;// 清除批量队列的标志
      e = next;
    }
  }
  // 处理普通订阅者队列并执行更新
  let error;
  while (batchedSub) {
    let e = batchedSub;
    batchedSub = void 0; // 清空队列
    while (e) {
      const next = e.next;
      e.next = void 0; // 重置链表指针
      e.flags &= -9; // 清除批量队列的标志
      // 若订阅者标记为需要触发更新,则执行更新,调用订阅者的trigger方法
      if (e.flags & 1) {
        try {
          ;
          e.trigger();
        } catch (err) {
          // 暂存错误  
          if (!error) error = err;
        }
      }
      // 遍历下一个订阅者
      e = next;
    }
  }
  // 处理错误
  if (error) throw error;
}

网站公告

今日签到

点亮在社区的每一天
去签到