Perf: Optimize nested each scope sync and add telemetry
This commit is contained in:
parent
c0d089a990
commit
548afb97ed
@ -1,5 +1,12 @@
|
||||
# CHANGELOG
|
||||
|
||||
## v1.0.11 (2026-05-21)
|
||||
|
||||
### 核心优化
|
||||
- **嵌套作用域同步**: 彻底重构了 `$each` 指令在节点复用时的上下文同步机制。现在复用节点会主动感知并合并父级作用域变量(`_ref`)的变更,解决了在虚拟滚动场景下嵌套 `$each` 数据不更新的严重 Bug。
|
||||
- **按需扫描机制**: 引入了变更感知逻辑,只有当迭代项引用变化或父级上下文变量变化时才触发子树扫描(`_scanTree`),大幅提升了复杂嵌套组件的滚动性能。
|
||||
- **性能遥测系统**: 在 `dom.js` 中内置了 `__statePerformanceTelemetry` 埋点,支持实时监控 `scanCount`(扫描)、`reuseCount`(复用)和 `moveCount`(DOM 移动)等核心指标,为极致性能调优提供数据支撑。
|
||||
|
||||
## v1.0.10 (2026-05-18)
|
||||
|
||||
### 修复
|
||||
|
||||
24
src/dom.js
24
src/dom.js
@ -119,20 +119,32 @@ export function _updateBinding(binding) {
|
||||
const rawKey = keyName ? (item && typeof item === 'object' ? item[keyName] : item) : k;
|
||||
// Safety: Handle potential duplicate keys or undefined keys
|
||||
const keyVal = (rawKey === undefined || rawKey === null || newKeyedNodes.has(rawKey)) ? `st_key_fallback_${i}_${Math.random()}` : rawKey;
|
||||
|
||||
|
||||
let existingNodes = node._keyedNodes.get(keyVal);
|
||||
|
||||
if (existingNodes) {
|
||||
// Reuse existing nodes
|
||||
node._keyedNodes.delete(keyVal);
|
||||
existingNodes.forEach(child => {
|
||||
child._ref[indexName] = k;
|
||||
// If data reference hasn't changed, skip heavy scan
|
||||
if (child._ref[asName] !== item) {
|
||||
if (window.__statePerformanceTelemetry) window.__statePerformanceTelemetry.reuseCount++;
|
||||
let scopeChanged = false;
|
||||
for (let key in node._ref) {
|
||||
if (key === asName || key === indexName) continue;
|
||||
if (child._ref[key] !== node._ref[key]) {
|
||||
child._ref[key] = node._ref[key];
|
||||
scopeChanged = true;
|
||||
}
|
||||
}
|
||||
const indexChanged = child._ref[indexName] !== k;
|
||||
if (indexChanged) child._ref[indexName] = k;
|
||||
|
||||
if (child._ref[asName] !== item || scopeChanged) {
|
||||
child._ref[asName] = item;
|
||||
if (window.__statePerformanceTelemetry) window.__statePerformanceTelemetry.scanCount++;
|
||||
_scanTree(child, { thisObj: node._thisObj, extendVars: child._ref });
|
||||
} else if (node.parentNode.lastChild !== child) {
|
||||
// Just move to the end to maintain order
|
||||
if (window.__statePerformanceTelemetry) window.__statePerformanceTelemetry.moveCount++;
|
||||
node.parentNode.insertBefore(child, node);
|
||||
}
|
||||
});
|
||||
@ -346,9 +358,9 @@ export const _scanTree = (node, scanObj = {}) => {
|
||||
node._ref = curr ? { ...curr._ref } : {};
|
||||
}
|
||||
if (scanObj.extendVars) Object.assign(node._ref, scanObj.extendVars);
|
||||
|
||||
|
||||
_parseNode(node, scanObj);
|
||||
|
||||
|
||||
const nodes = [...(node.childNodes || [])];
|
||||
const nextScanObj = { thisObj: scanObj.thisObj, extendVars: { ...node._ref } };
|
||||
nodes.forEach(child => {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user