release: v1.0.14 By: AICoder
This commit is contained in:
parent
b04be8d437
commit
a777f315b4
@ -1,5 +1,11 @@
|
|||||||
# CHANGELOG
|
# CHANGELOG
|
||||||
|
|
||||||
|
## v1.0.14 (2026-06-05)
|
||||||
|
|
||||||
|
### 修复
|
||||||
|
- **微任务扫描死循环**: 引入 `_stScanned` 标记对新挂载节点进行幂等拦截,防止在复杂嵌套(如 `$if` / `$each`)及大数据量场景下,新老节点重组重排循环触发 MutationObserver 造成浏览器卡死的微任务无限扫描死循环。
|
||||||
|
- **状态更新防御**: 在 `_updateBinding` 逻辑中加入同值校验,避免当目标值与原值相等时重复赋值,杜绝不必要的 Observer 触发与重绘。
|
||||||
|
|
||||||
## v1.0.13 (2026-05-26)
|
## v1.0.13 (2026-05-26)
|
||||||
|
|
||||||
### 新特性
|
### 新特性
|
||||||
|
|||||||
10
dist/state.js
vendored
10
dist/state.js
vendored
@ -244,7 +244,9 @@
|
|||||||
if (typeof result === "object" && result != null && !Array.isArray(result) && o[lk] == null) o[lk] = {};
|
if (typeof result === "object" && result != null && !Array.isArray(result) && o[lk] == null) o[lk] = {};
|
||||||
const lo = o[lk];
|
const lo = o[lk];
|
||||||
if (typeof lo === "object" && lo != null && lo.__watch) Object.assign(lo, result);
|
if (typeof lo === "object" && lo != null && lo.__watch) Object.assign(lo, result);
|
||||||
else o[lk] = result;
|
else {
|
||||||
|
if (o[lk] !== result) o[lk] = result;
|
||||||
|
}
|
||||||
} else if (typeof result === "object" && result != null && !Array.isArray(result)) {
|
} else if (typeof result === "object" && result != null && !Array.isArray(result)) {
|
||||||
Object.assign(o, result);
|
Object.assign(o, result);
|
||||||
}
|
}
|
||||||
@ -475,6 +477,7 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (node.nodeType !== 1) return;
|
if (node.nodeType !== 1) return;
|
||||||
|
node._stScanned = true;
|
||||||
if (!node._stTranslated) {
|
if (!node._stTranslated) {
|
||||||
Array.from(node.attributes).forEach((attr) => {
|
Array.from(node.attributes).forEach((attr) => {
|
||||||
if (!attr.name.startsWith("$") && !attr.name.startsWith("st-") && !attr.name.startsWith(".")) {
|
if (!attr.name.startsWith("$") && !attr.name.startsWith("st-") && !attr.name.startsWith(".")) {
|
||||||
@ -693,7 +696,10 @@
|
|||||||
new MutationObserver((mutations) => {
|
new MutationObserver((mutations) => {
|
||||||
mutations.forEach((mutation) => {
|
mutations.forEach((mutation) => {
|
||||||
mutation.addedNodes.forEach((newNode) => {
|
mutation.addedNodes.forEach((newNode) => {
|
||||||
if (newNode.isConnected) _scanTree(newNode);
|
if (newNode.isConnected && newNode.nodeType === 1 && !newNode._stScanned) {
|
||||||
|
newNode._stScanned = true;
|
||||||
|
_scanTree(newNode);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
mutation.removedNodes.forEach((oldNode) => _unbindTree(oldNode));
|
mutation.removedNodes.forEach((oldNode) => _unbindTree(oldNode));
|
||||||
});
|
});
|
||||||
|
|||||||
2
dist/state.min.js
vendored
2
dist/state.min.js
vendored
File diff suppressed because one or more lines are too long
2
dist/state.min.mjs
vendored
2
dist/state.min.mjs
vendored
File diff suppressed because one or more lines are too long
10
dist/state.mjs
vendored
10
dist/state.mjs
vendored
@ -240,7 +240,9 @@ function _updateBinding(binding) {
|
|||||||
if (typeof result === "object" && result != null && !Array.isArray(result) && o[lk] == null) o[lk] = {};
|
if (typeof result === "object" && result != null && !Array.isArray(result) && o[lk] == null) o[lk] = {};
|
||||||
const lo = o[lk];
|
const lo = o[lk];
|
||||||
if (typeof lo === "object" && lo != null && lo.__watch) Object.assign(lo, result);
|
if (typeof lo === "object" && lo != null && lo.__watch) Object.assign(lo, result);
|
||||||
else o[lk] = result;
|
else {
|
||||||
|
if (o[lk] !== result) o[lk] = result;
|
||||||
|
}
|
||||||
} else if (typeof result === "object" && result != null && !Array.isArray(result)) {
|
} else if (typeof result === "object" && result != null && !Array.isArray(result)) {
|
||||||
Object.assign(o, result);
|
Object.assign(o, result);
|
||||||
}
|
}
|
||||||
@ -471,6 +473,7 @@ const _scanTree = (node, scanObj = {}) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (node.nodeType !== 1) return;
|
if (node.nodeType !== 1) return;
|
||||||
|
node._stScanned = true;
|
||||||
if (!node._stTranslated) {
|
if (!node._stTranslated) {
|
||||||
Array.from(node.attributes).forEach((attr) => {
|
Array.from(node.attributes).forEach((attr) => {
|
||||||
if (!attr.name.startsWith("$") && !attr.name.startsWith("st-") && !attr.name.startsWith(".")) {
|
if (!attr.name.startsWith("$") && !attr.name.startsWith("st-") && !attr.name.startsWith(".")) {
|
||||||
@ -689,7 +692,10 @@ if (typeof document !== "undefined") {
|
|||||||
new MutationObserver((mutations) => {
|
new MutationObserver((mutations) => {
|
||||||
mutations.forEach((mutation) => {
|
mutations.forEach((mutation) => {
|
||||||
mutation.addedNodes.forEach((newNode) => {
|
mutation.addedNodes.forEach((newNode) => {
|
||||||
if (newNode.isConnected) _scanTree(newNode);
|
if (newNode.isConnected && newNode.nodeType === 1 && !newNode._stScanned) {
|
||||||
|
newNode._stScanned = true;
|
||||||
|
_scanTree(newNode);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
mutation.removedNodes.forEach((oldNode) => _unbindTree(oldNode));
|
mutation.removedNodes.forEach((oldNode) => _unbindTree(oldNode));
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@apigo.cc/state",
|
"name": "@apigo.cc/state",
|
||||||
"version": "1.0.13",
|
"version": "1.0.14",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/state.js",
|
"main": "dist/state.js",
|
||||||
"module": "dist/state.js",
|
"module": "dist/state.js",
|
||||||
|
|||||||
@ -76,7 +76,7 @@ export function _updateBinding(binding) {
|
|||||||
if (typeof result === 'object' && result != null && !Array.isArray(result) && o[lk] == null) o[lk] = {};
|
if (typeof result === 'object' && result != null && !Array.isArray(result) && o[lk] == null) o[lk] = {};
|
||||||
const lo = o[lk];
|
const lo = o[lk];
|
||||||
if (typeof lo === 'object' && lo != null && lo.__watch) Object.assign(lo, result);
|
if (typeof lo === 'object' && lo != null && lo.__watch) Object.assign(lo, result);
|
||||||
else o[lk] = result;
|
else { if (o[lk] !== result) o[lk] = result; }
|
||||||
} else if (typeof result === 'object' && result != null && !Array.isArray(result)) {
|
} else if (typeof result === 'object' && result != null && !Array.isArray(result)) {
|
||||||
Object.assign(o, result);
|
Object.assign(o, result);
|
||||||
}
|
}
|
||||||
@ -308,6 +308,7 @@ export const _scanTree = (node, scanObj = {}) => {
|
|||||||
node._stTranslated = true; return;
|
node._stTranslated = true; return;
|
||||||
}
|
}
|
||||||
if (node.nodeType !== 1) return;
|
if (node.nodeType !== 1) return;
|
||||||
|
node._stScanned = true;
|
||||||
|
|
||||||
if (!node._stTranslated) {
|
if (!node._stTranslated) {
|
||||||
Array.from(node.attributes).forEach(attr => {
|
Array.from(node.attributes).forEach(attr => {
|
||||||
|
|||||||
@ -28,7 +28,10 @@ if (typeof document !== 'undefined') {
|
|||||||
new MutationObserver(mutations => {
|
new MutationObserver(mutations => {
|
||||||
mutations.forEach(mutation => {
|
mutations.forEach(mutation => {
|
||||||
mutation.addedNodes.forEach(newNode => {
|
mutation.addedNodes.forEach(newNode => {
|
||||||
if (newNode.isConnected) _scanTree(newNode);
|
if (newNode.isConnected && newNode.nodeType === 1 && !newNode._stScanned) {
|
||||||
|
newNode._stScanned = true;
|
||||||
|
_scanTree(newNode);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
mutation.removedNodes.forEach(oldNode => _unbindTree(oldNode));
|
mutation.removedNodes.forEach(oldNode => _unbindTree(oldNode));
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user