@dooboostore/dom-render 1.0.110 → 1.0.112
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.MD +1 -2
- package/dist/cjs/DomRenderProxy.js +89 -48
- package/dist/cjs/DomRenderProxy.js.map +2 -2
- package/dist/cjs/components/ComponentBase.js +47 -1
- package/dist/cjs/components/ComponentBase.js.map +2 -2
- package/dist/cjs/components/a/A.js +22 -0
- package/dist/cjs/components/a/A.js.map +2 -2
- package/dist/cjs/components/appender/Appender.js +21 -4
- package/dist/cjs/components/appender/Appender.js.map +2 -2
- package/dist/cjs/components/details/Details.js +5 -0
- package/dist/cjs/components/details/Details.js.map +2 -2
- package/dist/cjs/components/forOf/ForOf.js +2 -2
- package/dist/cjs/components/forOf/ForOf.js.map +1 -1
- package/dist/cjs/components/if/If.js +1 -1
- package/dist/cjs/components/if/If.js.map +2 -2
- package/dist/cjs/components/index.js +3 -1
- package/dist/cjs/components/index.js.map +3 -3
- package/dist/cjs/components/router/RouterOutlet.js +41 -10
- package/dist/cjs/components/router/RouterOutlet.js.map +2 -2
- package/dist/cjs/components/select/Select.js +39 -1
- package/dist/cjs/components/select/Select.js.map +2 -2
- package/dist/cjs/components/this/This.js +33 -5
- package/dist/cjs/components/this/This.js.map +2 -2
- package/dist/cjs/decorators/DomRenderNoProxy.js +3 -9
- package/dist/cjs/decorators/DomRenderNoProxy.js.map +2 -2
- package/dist/cjs/events/EventManager.js +103 -37
- package/dist/cjs/events/EventManager.js.map +2 -2
- package/dist/cjs/lifecycle/OnChangeAttrRender.js.map +1 -1
- package/dist/cjs/lifecycle/OnChildRawSetRendered.js +26 -0
- package/dist/cjs/lifecycle/OnChildRawSetRendered.js.map +7 -0
- package/dist/cjs/lifecycle/OnRawSetRendered.js.map +2 -2
- package/dist/cjs/operators/Appender.js +8 -1
- package/dist/cjs/operators/Appender.js.map +2 -2
- package/dist/cjs/operators/Dr.js +2 -2
- package/dist/cjs/operators/Dr.js.map +2 -2
- package/dist/cjs/operators/DrAppender.js +2 -2
- package/dist/cjs/operators/DrAppender.js.map +2 -2
- package/dist/cjs/operators/DrFor.js +2 -2
- package/dist/cjs/operators/DrFor.js.map +2 -2
- package/dist/cjs/operators/DrForOf.js +34 -6
- package/dist/cjs/operators/DrForOf.js.map +2 -2
- package/dist/cjs/operators/DrForm.js +6 -6
- package/dist/cjs/operators/DrForm.js.map +2 -2
- package/dist/cjs/operators/DrInnerHTML.js +2 -2
- package/dist/cjs/operators/DrInnerHTML.js.map +2 -2
- package/dist/cjs/operators/DrRepeat.js +2 -2
- package/dist/cjs/operators/DrRepeat.js.map +2 -2
- package/dist/cjs/operators/DrStripElement.js +2 -2
- package/dist/cjs/operators/DrStripElement.js.map +2 -2
- package/dist/cjs/operators/DrTargetElement.js +14 -5
- package/dist/cjs/operators/DrTargetElement.js.map +2 -2
- package/dist/cjs/operators/DrTargetElementIsElement.js +2 -2
- package/dist/cjs/operators/DrTargetElementIsElement.js.map +2 -2
- package/dist/cjs/operators/DrThis.js +2 -2
- package/dist/cjs/operators/DrThis.js.map +2 -2
- package/dist/cjs/operators/DrThisProperty.js +2 -1
- package/dist/cjs/operators/DrThisProperty.js.map +2 -2
- package/dist/cjs/rawsets/RawSet.js +87 -160
- package/dist/cjs/rawsets/RawSet.js.map +2 -2
- package/dist/cjs/routers/HashRouter.js +3 -0
- package/dist/cjs/routers/HashRouter.js.map +2 -2
- package/dist/cjs/routers/PathRouter.js +3 -0
- package/dist/cjs/routers/PathRouter.js.map +2 -2
- package/dist/cjs/routers/Router.js +25 -21
- package/dist/cjs/routers/Router.js.map +2 -2
- package/dist/esm/DomRenderProxy.js +89 -48
- package/dist/esm/DomRenderProxy.js.map +2 -2
- package/dist/esm/components/ComponentBase.js +47 -1
- package/dist/esm/components/ComponentBase.js.map +2 -2
- package/dist/esm/components/a/A.js +22 -0
- package/dist/esm/components/a/A.js.map +2 -2
- package/dist/esm/components/appender/Appender.js +22 -5
- package/dist/esm/components/appender/Appender.js.map +2 -2
- package/dist/esm/components/details/Details.js +5 -0
- package/dist/esm/components/details/Details.js.map +2 -2
- package/dist/esm/components/forOf/ForOf.js +2 -2
- package/dist/esm/components/forOf/ForOf.js.map +1 -1
- package/dist/esm/components/if/If.js +1 -1
- package/dist/esm/components/if/If.js.map +2 -2
- package/dist/esm/components/index.js +3 -1
- package/dist/esm/components/index.js.map +2 -2
- package/dist/esm/components/router/RouterOutlet.js +41 -10
- package/dist/esm/components/router/RouterOutlet.js.map +2 -2
- package/dist/esm/components/select/Select.js +39 -1
- package/dist/esm/components/select/Select.js.map +2 -2
- package/dist/esm/components/this/This.js +33 -5
- package/dist/esm/components/this/This.js.map +2 -2
- package/dist/esm/decorators/DomRenderNoProxy.js +3 -9
- package/dist/esm/decorators/DomRenderNoProxy.js.map +2 -2
- package/dist/esm/events/EventManager.js +103 -37
- package/dist/esm/events/EventManager.js.map +2 -2
- package/dist/esm/lifecycle/OnChangeAttrRender.js.map +1 -1
- package/dist/esm/lifecycle/OnChildRawSetRendered.js +7 -0
- package/dist/esm/lifecycle/OnChildRawSetRendered.js.map +7 -0
- package/dist/esm/lifecycle/OnRawSetRendered.js.map +2 -2
- package/dist/esm/operators/Appender.js +8 -1
- package/dist/esm/operators/Appender.js.map +2 -2
- package/dist/esm/operators/Dr.js +2 -2
- package/dist/esm/operators/Dr.js.map +2 -2
- package/dist/esm/operators/DrAppender.js +2 -2
- package/dist/esm/operators/DrAppender.js.map +2 -2
- package/dist/esm/operators/DrFor.js +2 -2
- package/dist/esm/operators/DrFor.js.map +2 -2
- package/dist/esm/operators/DrForOf.js +34 -6
- package/dist/esm/operators/DrForOf.js.map +2 -2
- package/dist/esm/operators/DrForm.js +6 -6
- package/dist/esm/operators/DrForm.js.map +2 -2
- package/dist/esm/operators/DrInnerHTML.js +2 -2
- package/dist/esm/operators/DrInnerHTML.js.map +2 -2
- package/dist/esm/operators/DrRepeat.js +2 -2
- package/dist/esm/operators/DrRepeat.js.map +2 -2
- package/dist/esm/operators/DrStripElement.js +2 -2
- package/dist/esm/operators/DrStripElement.js.map +2 -2
- package/dist/esm/operators/DrTargetElement.js +14 -5
- package/dist/esm/operators/DrTargetElement.js.map +2 -2
- package/dist/esm/operators/DrTargetElementIsElement.js +2 -2
- package/dist/esm/operators/DrTargetElementIsElement.js.map +2 -2
- package/dist/esm/operators/DrThis.js +2 -2
- package/dist/esm/operators/DrThis.js.map +2 -2
- package/dist/esm/operators/DrThisProperty.js +2 -1
- package/dist/esm/operators/DrThisProperty.js.map +2 -2
- package/dist/esm/rawsets/RawSet.js +87 -160
- package/dist/esm/rawsets/RawSet.js.map +2 -2
- package/dist/esm/routers/HashRouter.js +3 -0
- package/dist/esm/routers/HashRouter.js.map +2 -2
- package/dist/esm/routers/PathRouter.js +3 -0
- package/dist/esm/routers/PathRouter.js.map +2 -2
- package/dist/esm/routers/Router.js +25 -21
- package/dist/esm/routers/Router.js.map +2 -2
- package/dist/esm-bundle/dooboostore-dom-render.esm.js +830 -1533
- package/dist/esm-bundle/dooboostore-dom-render.esm.js.map +4 -4
- package/dist/types/DomRenderProxy.d.ts.map +1 -1
- package/dist/types/components/ComponentBase.d.ts +12 -1
- package/dist/types/components/ComponentBase.d.ts.map +1 -1
- package/dist/types/components/a/A.d.ts +6 -0
- package/dist/types/components/a/A.d.ts.map +1 -1
- package/dist/types/components/appender/Appender.d.ts +1 -0
- package/dist/types/components/appender/Appender.d.ts.map +1 -1
- package/dist/types/components/details/Details.d.ts +2 -0
- package/dist/types/components/details/Details.d.ts.map +1 -1
- package/dist/types/components/forOf/ForOf.d.ts +1 -1
- package/dist/types/components/forOf/ForOf.d.ts.map +1 -1
- package/dist/types/components/if/If.d.ts.map +1 -1
- package/dist/types/components/index.d.ts +1 -0
- package/dist/types/components/index.d.ts.map +1 -1
- package/dist/types/components/router/RouterOutlet.d.ts +6 -3
- package/dist/types/components/router/RouterOutlet.d.ts.map +1 -1
- package/dist/types/components/select/Select.d.ts +5 -3
- package/dist/types/components/select/Select.d.ts.map +1 -1
- package/dist/types/components/this/This.d.ts +5 -1
- package/dist/types/components/this/This.d.ts.map +1 -1
- package/dist/types/decorators/DomRenderNoProxy.d.ts.map +1 -1
- package/dist/types/events/EventManager.d.ts +1 -0
- package/dist/types/events/EventManager.d.ts.map +1 -1
- package/dist/types/lifecycle/OnChangeAttrRender.d.ts +1 -1
- package/dist/types/lifecycle/OnChangeAttrRender.d.ts.map +1 -1
- package/dist/types/lifecycle/OnChildRawSetRendered.d.ts +9 -0
- package/dist/types/lifecycle/OnChildRawSetRendered.d.ts.map +1 -0
- package/dist/types/lifecycle/OnRawSetRendered.d.ts +2 -0
- package/dist/types/lifecycle/OnRawSetRendered.d.ts.map +1 -1
- package/dist/types/operators/Appender.d.ts +1 -0
- package/dist/types/operators/Appender.d.ts.map +1 -1
- package/dist/types/operators/Dr.d.ts.map +1 -1
- package/dist/types/operators/DrAppender.d.ts.map +1 -1
- package/dist/types/operators/DrFor.d.ts.map +1 -1
- package/dist/types/operators/DrForOf.d.ts.map +1 -1
- package/dist/types/operators/DrForm.d.ts.map +1 -1
- package/dist/types/operators/DrInnerHTML.d.ts.map +1 -1
- package/dist/types/operators/DrRepeat.d.ts.map +1 -1
- package/dist/types/operators/DrStripElement.d.ts.map +1 -1
- package/dist/types/operators/DrTargetElement.d.ts.map +1 -1
- package/dist/types/operators/DrThisProperty.d.ts.map +1 -1
- package/dist/types/rawsets/RawSet.d.ts +4 -1
- package/dist/types/rawsets/RawSet.d.ts.map +1 -1
- package/dist/types/routers/HashRouter.d.ts +1 -0
- package/dist/types/routers/HashRouter.d.ts.map +1 -1
- package/dist/types/routers/PathRouter.d.ts +1 -0
- package/dist/types/routers/PathRouter.d.ts.map +1 -1
- package/dist/types/routers/Router.d.ts +3 -0
- package/dist/types/routers/Router.d.ts.map +1 -1
- package/dist/umd-bundle/dooboostore-dom-render.umd.js +830 -1533
- package/dist/umd-bundle/dooboostore-dom-render.umd.js.map +4 -4
- package/package.json +4 -4
- package/src/DomRenderProxy.ts +169 -75
- package/src/DomRenderProxy.ts_cache_back +1031 -0
- package/src/components/ComponentBase.ts +61 -5
- package/src/components/a/A.ts +25 -0
- package/src/components/appender/Appender.ts +3 -3
- package/src/components/details/Details.ts +7 -0
- package/src/components/forOf/ForOf.ts +2 -2
- package/src/components/if/If.ts +3 -2
- package/src/components/index.ts +3 -0
- package/src/components/router/RouterOutlet.ts +60 -22
- package/src/components/select/Select.ts +69 -30
- package/src/components/this/This.ts +41 -6
- package/src/decorators/DomRenderNoProxy.ts +17 -14
- package/src/events/EventManager.ts +180 -77
- package/src/lifecycle/OnChangeAttrRender.ts +1 -1
- package/src/lifecycle/OnChildRawSetRendered.ts +13 -0
- package/src/lifecycle/OnRawSetRendered.ts +3 -1
- package/src/operators/Appender.ts +8 -1
- package/src/operators/Dr.ts +2 -1
- package/src/operators/DrAppender.ts +2 -1
- package/src/operators/DrFor.ts +2 -1
- package/src/operators/DrForOf.ts +36 -6
- package/src/operators/DrForm.ts +6 -5
- package/src/operators/DrInnerHTML.ts +2 -1
- package/src/operators/DrRepeat.ts +2 -1
- package/src/operators/DrStripElement.ts +2 -1
- package/src/operators/DrTargetElement.ts +17 -5
- package/src/operators/DrTargetElementIsElement.ts +2 -2
- package/src/operators/DrThis.ts +2 -2
- package/src/operators/DrThisProperty.ts +2 -1
- package/src/rawsets/RawSet.ts +161 -237
- package/src/routers/HashRouter.ts +4 -0
- package/src/routers/PathRouter.ts +5 -0
- package/src/routers/Router.ts +64 -47
- package/src/node_modules/.bin/acorn +0 -17
- package/src/node_modules/.bin/browserslist +0 -17
- package/src/node_modules/.bin/eslint +0 -17
- package/src/node_modules/.bin/sbf +0 -17
- package/src/node_modules/.bin/ts-node +0 -17
- package/src/node_modules/.bin/ts-node-cwd +0 -17
- package/src/node_modules/.bin/ts-node-dev +0 -17
- package/src/node_modules/.bin/ts-node-esm +0 -17
- package/src/node_modules/.bin/ts-node-script +0 -17
- package/src/node_modules/.bin/ts-node-transpile-only +0 -17
- package/src/node_modules/.bin/ts-script +0 -17
- package/src/node_modules/.bin/tsc +0 -17
- package/src/node_modules/.bin/tsnd +0 -17
- package/src/node_modules/.bin/tsserver +0 -17
- package/src/node_modules/.bin/webpack +0 -17
- package/src/node_modules/.bin/webpack-cli +0 -17
- package/src/node_modules/.bin/webpack-dev-server +0 -17
|
@@ -0,0 +1,1031 @@
|
|
|
1
|
+
import { RawSet, RenderResult } from './rawsets/RawSet';
|
|
2
|
+
import { EventManager, NormalAttrDataType } from './events/EventManager';
|
|
3
|
+
import { DomRenderConfig } from './configs/DomRenderConfig';
|
|
4
|
+
import { ScriptUtils } from '@dooboostore/core-web/script/ScriptUtils';
|
|
5
|
+
import { DomRenderFinalProxy, Shield } from './types/Types';
|
|
6
|
+
import { RawSetType } from './rawsets/RawSetType';
|
|
7
|
+
import { DrThisProperty } from './operators/DrThisProperty';
|
|
8
|
+
import { RawSetOperatorType } from './rawsets/RawSetOperatorType';
|
|
9
|
+
import { ComponentSet } from './components/ComponentSet';
|
|
10
|
+
import { DomRenderNoProxyKey, isDomRenderNoProxy } from './decorators/DomRenderNoProxy';
|
|
11
|
+
import { isOnCreateRender } from './lifecycle/OnCreateRender';
|
|
12
|
+
import { isOnInitRender } from './lifecycle/OnInitRender';
|
|
13
|
+
import { isOnCreateRenderData } from './lifecycle/OnCreateRenderData';
|
|
14
|
+
import { isOnChangeAttrRender } from './lifecycle/OnChangeAttrRender';
|
|
15
|
+
import { DocumentUtils } from '@dooboostore/core-web/document/DocumentUtils';
|
|
16
|
+
import { isDefined } from '@dooboostore/core/types';
|
|
17
|
+
import { isOnBeforeReturnSet } from './lifecycle/OnBeforeReturnSet';
|
|
18
|
+
import { isOnChildRenderedByProperty } from './lifecycle/OnChildRenderedByProperty';
|
|
19
|
+
import { ObjectUtils } from '@dooboostore/core/object/ObjectUtils';
|
|
20
|
+
import { ValidUtils } from '@dooboostore/core/valid/ValidUtils';
|
|
21
|
+
import { isOnProxyDomRender } from './lifecycle/OnProxyDomRender';
|
|
22
|
+
import { isOnRawSetRendered } from './lifecycle/OnRawSetRendered';
|
|
23
|
+
|
|
24
|
+
const excludeGetSetPropertys = [
|
|
25
|
+
'onBeforeReturnGet',
|
|
26
|
+
'onBeforeReturnSet',
|
|
27
|
+
'__domrender_components',
|
|
28
|
+
'__render',
|
|
29
|
+
'_DomRender_isFinal',
|
|
30
|
+
'_domRender_ref',
|
|
31
|
+
'_rawSets',
|
|
32
|
+
'_domRender_proxy',
|
|
33
|
+
'_targets',
|
|
34
|
+
'_DomRender_origin',
|
|
35
|
+
'_DomRender_ref',
|
|
36
|
+
'_DomRender_proxy'
|
|
37
|
+
];
|
|
38
|
+
export const isWrapProxyDomRenderProxy = <T>(obj: T): boolean => {
|
|
39
|
+
return obj && typeof obj === 'object' && '_DomRender_isProxy' in obj;
|
|
40
|
+
};
|
|
41
|
+
export const getDomRenderOriginObject = <T>(obj: T): T => {
|
|
42
|
+
if (isWrapProxyDomRenderProxy(obj)) {
|
|
43
|
+
return (obj as any)._domRender_origin;
|
|
44
|
+
}
|
|
45
|
+
return obj;
|
|
46
|
+
};
|
|
47
|
+
export const getDomRenderConfig = (obj: any): DomRenderConfig | undefined => {
|
|
48
|
+
if (isWrapProxyDomRenderProxy(obj)) {
|
|
49
|
+
return obj._domRender_config;
|
|
50
|
+
}
|
|
51
|
+
return undefined;
|
|
52
|
+
};
|
|
53
|
+
//@ts-ignore
|
|
54
|
+
export const getDomRenderProxy = <T>(obj: T): DomRenderProxy<T> | undefined => {
|
|
55
|
+
if (isWrapProxyDomRenderProxy(obj)) {
|
|
56
|
+
//@ts-ignore
|
|
57
|
+
return (obj as any)._domRender_proxy as DomRenderProxy<T>;
|
|
58
|
+
}
|
|
59
|
+
return undefined;
|
|
60
|
+
};
|
|
61
|
+
export class DomRenderProxy<T extends object> implements ProxyHandler<T> {
|
|
62
|
+
public _domRender_ref = new Map<object, Set<string>>();
|
|
63
|
+
public _rawSets = new Map<string, Set<RawSet>>();
|
|
64
|
+
public _domRender_proxy?: T;
|
|
65
|
+
// public _firstTarget: Node;
|
|
66
|
+
public _targets = new Set<Node>();
|
|
67
|
+
|
|
68
|
+
// 중복 호출 방지를 위한 전역 캐시
|
|
69
|
+
private static _processingPaths = new Set<string>();
|
|
70
|
+
private static _lastProcessTime = new Map<string, number>();
|
|
71
|
+
|
|
72
|
+
// DOM 요소 캐싱
|
|
73
|
+
private _elementCache = new WeakMap<Element, { elements: any, timestamp: number }>();
|
|
74
|
+
private static _globalElementCache = new WeakMap<Element, { elements: any, timestamp: number }>();
|
|
75
|
+
|
|
76
|
+
// 배치 처리를 위한 필드들
|
|
77
|
+
private static _pendingUpdates = new Map<string, { value: any, timestamp: number, proxies: Set<DomRenderProxy<any>> }>();
|
|
78
|
+
private static _batchUpdateScheduled = false;
|
|
79
|
+
private static _batchTimeout: any = null;
|
|
80
|
+
|
|
81
|
+
constructor(
|
|
82
|
+
public _domRender_origin: T,
|
|
83
|
+
target: Node | null | undefined,
|
|
84
|
+
public _domRender_config: DomRenderConfig
|
|
85
|
+
) {
|
|
86
|
+
if (target) {
|
|
87
|
+
this._targets.add(target);
|
|
88
|
+
// this._firstTarget = target;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// setInterval(() => {
|
|
92
|
+
// this._rawSets.forEach(it => {
|
|
93
|
+
// Array.from(it).forEach(it => {
|
|
94
|
+
// console.log(it, it.isConnected)
|
|
95
|
+
// })
|
|
96
|
+
// });
|
|
97
|
+
// }, 1000)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
public static unFinal<T = any>(obj: T): T {
|
|
101
|
+
return DomRenderFinalProxy.unFinal(obj);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
public static final<T = any>(obj: T): T {
|
|
105
|
+
return DomRenderFinalProxy.final(obj);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
public static isFinal<T = any>(obj: T) {
|
|
109
|
+
return ValidUtils.isNull(obj) || DomRenderFinalProxy.isFinal(obj);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
public async run(objProxy: T) {
|
|
113
|
+
this._domRender_proxy = objProxy;
|
|
114
|
+
if (isOnProxyDomRender(objProxy)) {
|
|
115
|
+
objProxy.onProxyDomRender(this._domRender_config);
|
|
116
|
+
}
|
|
117
|
+
const obj = getDomRenderOriginObject<any>(objProxy);
|
|
118
|
+
if (obj) {
|
|
119
|
+
Object.keys(obj).forEach(it => {
|
|
120
|
+
// Reflect 메타데이터에서 domRender:NoProxy 여부 확인
|
|
121
|
+
try {
|
|
122
|
+
const isNoProxy =
|
|
123
|
+
Reflect.getMetadata(DomRenderNoProxyKey, obj, it) ||
|
|
124
|
+
Reflect.getMetadata(DomRenderNoProxyKey, Object.getPrototypeOf(obj).constructor);
|
|
125
|
+
if (isNoProxy) {
|
|
126
|
+
return obj;
|
|
127
|
+
}
|
|
128
|
+
} catch (e) { }
|
|
129
|
+
const target = obj[it];
|
|
130
|
+
if (
|
|
131
|
+
target !== undefined &&
|
|
132
|
+
target !== null &&
|
|
133
|
+
typeof target === 'object' &&
|
|
134
|
+
!DomRenderProxy.isFinal(target) &&
|
|
135
|
+
!Object.isFrozen(target) &&
|
|
136
|
+
!(obj instanceof Shield)
|
|
137
|
+
) {
|
|
138
|
+
const isExcluded = this._domRender_config.proxyExcludeTyps?.some(it => target instanceof it) ?? false;
|
|
139
|
+
// const filter = this._domRender_config.proxyExcludeTyps?.filter(it => target instanceof it) ?? [];
|
|
140
|
+
if (!isExcluded) {
|
|
141
|
+
const proxyAfter = this.proxy(objProxy, target, it);
|
|
142
|
+
obj[it] = proxyAfter;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
// console.log('target', this._targets);
|
|
148
|
+
for (let target of this._targets) {
|
|
149
|
+
await this.initRender(target);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
public async initRender(target: Node, rawSet?: RawSet) {
|
|
154
|
+
// if (target instanceof Element) {
|
|
155
|
+
// target.setAttribute('dr-this', 'this');
|
|
156
|
+
// const rawSets = RawSet.checkPointCreates(target, this._domRender_proxy, this.config);
|
|
157
|
+
// this.render(rawSets)
|
|
158
|
+
// return;
|
|
159
|
+
// }
|
|
160
|
+
//
|
|
161
|
+
if (target instanceof Element) {
|
|
162
|
+
// 중요: 나를통해 이어진곳의 위치를 남겨야된다 안그러면 TargetElement는 알수 있는 방법이 없다. 여기서 흔적을 남겨줘야 한다.
|
|
163
|
+
// const targetElementNames = (this.config.targetElements?.map(it => it.name.toLowerCase().replaceAll('.', '\\.')) ?? []).join(',');
|
|
164
|
+
// Array.from(target.querySelectorAll(targetElementNames)).forEach(it => it.setAttribute(EventManager.parentVariablePathAttrName, '@this@'));
|
|
165
|
+
target.innerHTML = target.innerHTML.replace(/@this@/g, 'this');
|
|
166
|
+
}
|
|
167
|
+
// TODO: 한곳에서 처리 필요할듯.. 너무 산발적으로 있음.
|
|
168
|
+
const onCreate = (target as any).getAttribute?.(RawSet.DR_ON_CREATE_ARGUMENTS_OPTIONNAME);
|
|
169
|
+
let createParam: any[] = [];
|
|
170
|
+
if (onCreate) {
|
|
171
|
+
createParam = ObjectUtils.Script.evaluateReturn(onCreate, this._domRender_proxy);
|
|
172
|
+
if (!Array.isArray(createParam)) {
|
|
173
|
+
createParam = [createParam];
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (isOnCreateRenderData(this._domRender_proxy)) {
|
|
178
|
+
this._domRender_proxy?.onCreateRenderData({ rootParent: this._domRender_proxy });
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (isOnCreateRender(this._domRender_proxy)) {
|
|
182
|
+
this._domRender_proxy.onCreateRender(...createParam);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// const innerHTML = (target as any).innerHTML ?? '';
|
|
186
|
+
this._targets.add(target);
|
|
187
|
+
const rawSets = RawSet.checkPointCreates(target, this._domRender_proxy, this._domRender_config);
|
|
188
|
+
// console.log('initRender -------rawSet', rawSets)
|
|
189
|
+
// 중요 초기에 한번 튕겨줘야함.
|
|
190
|
+
let attrElements;
|
|
191
|
+
if (target instanceof Element) {
|
|
192
|
+
const cached = DomRenderProxy._globalElementCache.get(target);
|
|
193
|
+
const now = Date.now();
|
|
194
|
+
|
|
195
|
+
if (cached && (now - cached.timestamp) < 100) { // 100ms 캐시
|
|
196
|
+
attrElements = cached.elements;
|
|
197
|
+
console.log(`💾 initRender: Using cached findAttrElements`);
|
|
198
|
+
} else {
|
|
199
|
+
attrElements = this._domRender_config.eventManager.findAttrElements(target, this._domRender_config);
|
|
200
|
+
DomRenderProxy._globalElementCache.set(target, { elements: attrElements, timestamp: now });
|
|
201
|
+
console.log(`🔍 initRender: Fresh findAttrElements`);
|
|
202
|
+
}
|
|
203
|
+
} else {
|
|
204
|
+
attrElements = this._domRender_config.eventManager.findAttrElements(target as Element, this._domRender_config);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
this._domRender_config.eventManager.applyEvent(
|
|
208
|
+
this._domRender_proxy,
|
|
209
|
+
attrElements,
|
|
210
|
+
this._domRender_config
|
|
211
|
+
);
|
|
212
|
+
rawSets.forEach(it => {
|
|
213
|
+
const variables = it.getUsingTriggerVariables(this._domRender_config);
|
|
214
|
+
if (variables.size <= 0) {
|
|
215
|
+
this.addRawSet('', it);
|
|
216
|
+
} else {
|
|
217
|
+
variables.forEach(sit => {
|
|
218
|
+
this.addRawSet(sit, it);
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
const targetRawSets = await this.render(this.getRawSets());
|
|
224
|
+
for (let targetRawSet of targetRawSets) {
|
|
225
|
+
const onInit = (target as any).getAttribute?.(RawSet.DR_ON_INIT_ARGUMENTS_OPTIONNAME);
|
|
226
|
+
let initParam: any;
|
|
227
|
+
if (onCreate) {
|
|
228
|
+
initParam = ScriptUtils.evaluateReturn(onCreate, this._domRender_proxy);
|
|
229
|
+
}
|
|
230
|
+
if (isOnInitRender(this._domRender_proxy)) {
|
|
231
|
+
await this._domRender_proxy.onInitRender(
|
|
232
|
+
initParam,
|
|
233
|
+
rawSet ?? ({ dataSet: { config: this._domRender_config } } as any)
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
public getRawSets() {
|
|
240
|
+
const set = new Set<RawSet>();
|
|
241
|
+
this._rawSets.forEach((v, k) => {
|
|
242
|
+
v.forEach(it => set.add(it));
|
|
243
|
+
});
|
|
244
|
+
return Array.from(set);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// 중요 important
|
|
248
|
+
public async render(raws?: RawSet[] | string, fullPathStr?: string) {
|
|
249
|
+
if (typeof raws === 'string') {
|
|
250
|
+
const iter = this._rawSets.get(raws);
|
|
251
|
+
if (iter) {
|
|
252
|
+
raws = Array.from(iter);
|
|
253
|
+
} else {
|
|
254
|
+
raws = undefined;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
const removeRawSets: RawSet[] = [];
|
|
258
|
+
const rawSets = raws ?? this.getRawSets();
|
|
259
|
+
|
|
260
|
+
// console.log('----', rawSets);
|
|
261
|
+
for (const it of rawSets as RawSet[]) {
|
|
262
|
+
it.getUsingTriggerVariables(this._domRender_config).forEach(path => {
|
|
263
|
+
// console.log('getUsingTriggerVariables->', path);
|
|
264
|
+
this.addRawSet(path, it);
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
let renderResult: RenderResult | undefined;
|
|
268
|
+
if (it.isConnected) {
|
|
269
|
+
// 중요 render될때 targetAttribute 체크 해야함.
|
|
270
|
+
const targetAttrMap = (it.point.node as Element)?.getAttribute?.(EventManager.normalAttrMapAttrName);
|
|
271
|
+
// console.log('sssssssssSSS?',it, targetAttrMap)
|
|
272
|
+
// console.log('----2', it, fullPathStr, targetAttrMap, (it.fragment as any).render, it.isConnected, this.getRawSets());
|
|
273
|
+
if (it.detect?.action) {
|
|
274
|
+
it.detect.action();
|
|
275
|
+
// } else if (it.type === RawSetType.TARGET_ELEMENT && it.data && fullPathStr && targetAttrMap && (it.fragment as any).render) {
|
|
276
|
+
} else if (
|
|
277
|
+
it.type === RawSetType.TARGET_ELEMENT &&
|
|
278
|
+
it.dataSet?.render?.currentThis &&
|
|
279
|
+
fullPathStr &&
|
|
280
|
+
targetAttrMap
|
|
281
|
+
) {
|
|
282
|
+
new Map<string, NormalAttrDataType>(JSON.parse(targetAttrMap)).forEach((v, k) => {
|
|
283
|
+
// it?.data.onChangeAttrRender(k, null, v);
|
|
284
|
+
// console.log('------->?',v,k);
|
|
285
|
+
const isUsing = v.variablePaths.some(it => EventManager.isUsingThisVar(it.inner, `this.${fullPathStr}`))
|
|
286
|
+
// console.log('------->?',v,k, isUsing);
|
|
287
|
+
if (isUsing) {
|
|
288
|
+
const targetAttrObject = RawSet.getAttributeObject(it.point.node as Element, {
|
|
289
|
+
script: it.dataSet?.render?.renderScript ?? '',
|
|
290
|
+
obj: Object.assign(this._domRender_proxy ?? {}, { __render: it.dataSet?.render })
|
|
291
|
+
});
|
|
292
|
+
it.dataSet.render ??= {};
|
|
293
|
+
it.dataSet.render.attribute = targetAttrObject;
|
|
294
|
+
// const render = it.dataSet?.render;
|
|
295
|
+
// console.log('render-->!!!!!', it.dataSet.render);
|
|
296
|
+
// const script = `${render.renderScript} return ${v} `;
|
|
297
|
+
// const cval = ScriptUtils.eval(script, Object.assign(this._domRender_proxy ?? {}, { __render: render }));
|
|
298
|
+
if (isOnChangeAttrRender(it.dataSet?.render?.currentThis)) {
|
|
299
|
+
it.dataSet?.render?.currentThis?.onChangeAttrRender?.(k, targetAttrObject[k], { rawSet: it });
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
// console.log('---?', v, fullPathStr, isUsing);
|
|
303
|
+
});
|
|
304
|
+
// ------------------->
|
|
305
|
+
} else {
|
|
306
|
+
const rawSets = await it.render(this._domRender_proxy, this._domRender_config);
|
|
307
|
+
renderResult = rawSets;
|
|
308
|
+
// 그외 자식들 render
|
|
309
|
+
if (rawSets && rawSets.raws.length > 0) {
|
|
310
|
+
await this.render(rawSets.raws);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
} else {
|
|
314
|
+
removeRawSets.push(it);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
const t = it.findNearThis(this._domRender_proxy);
|
|
318
|
+
// TODO: 호출된곳에서 또 변수를 수정하게되면 무한루프니깐 왠만하면 사용못하게 해야한다.
|
|
319
|
+
if (isOnRawSetRendered(t)) {
|
|
320
|
+
await t.onRawSetRendered(it, { path: fullPathStr, value: ObjectUtils.Script.evaluateReturn(`this.${fullPathStr}`, this._domRender_proxy), root: this._domRender_proxy, renderResult });
|
|
321
|
+
}
|
|
322
|
+
// console.log('----', it);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
if (removeRawSets.length > 0) {
|
|
326
|
+
this.removeRawSet(...removeRawSets);
|
|
327
|
+
}
|
|
328
|
+
return this.getRawSets();
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// domrender_ref로 찾는걸로 바꿈
|
|
332
|
+
// public findRootDomRenderProxy(): DomRenderProxy<any> {
|
|
333
|
+
// let current:DomRenderProxy<any> = this;
|
|
334
|
+
// while (current.parentProxy) {
|
|
335
|
+
// current = current.parentProxy;
|
|
336
|
+
// }
|
|
337
|
+
// return current;
|
|
338
|
+
// }
|
|
339
|
+
|
|
340
|
+
public root(
|
|
341
|
+
pathInfos: { path: string; obj: any }[][],
|
|
342
|
+
value?: any,
|
|
343
|
+
lastDoneExecute = true
|
|
344
|
+
): { path: string; obj: any }[][] {
|
|
345
|
+
const rootStartTime = Date.now();
|
|
346
|
+
const pathKey = pathInfos.flat().map(i => i.path).join('.');
|
|
347
|
+
|
|
348
|
+
console.group(`🌳 DomRenderProxy root: ${pathKey}`);
|
|
349
|
+
|
|
350
|
+
// 중복 호출 방지 체크
|
|
351
|
+
const now = Date.now();
|
|
352
|
+
const lastProcessTime = DomRenderProxy._lastProcessTime.get(pathKey);
|
|
353
|
+
|
|
354
|
+
if (DomRenderProxy._processingPaths.has(pathKey)) {
|
|
355
|
+
console.log(`🚫 Already processing path: ${pathKey}`);
|
|
356
|
+
console.groupEnd();
|
|
357
|
+
return [];
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// 배치 처리 중인 경우 체크
|
|
361
|
+
const pendingBatch = DomRenderProxy._pendingUpdates.get(pathKey);
|
|
362
|
+
if (pendingBatch && (now - pendingBatch.timestamp) < 5) { // 5ms 내 배치 처리 대기 중
|
|
363
|
+
console.log(`📦 Batch processing pending for: ${pathKey} (${now - pendingBatch.timestamp}ms ago)`);
|
|
364
|
+
console.groupEnd();
|
|
365
|
+
return [];
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
if (lastProcessTime && (now - lastProcessTime) < 10) { // 10ms 내 중복 방지
|
|
369
|
+
console.log(`🚫 Duplicate call prevented for: ${pathKey} (${now - lastProcessTime}ms ago)`);
|
|
370
|
+
console.groupEnd();
|
|
371
|
+
return [];
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// 처리 시작 마킹
|
|
375
|
+
DomRenderProxy._processingPaths.add(pathKey);
|
|
376
|
+
DomRenderProxy._lastProcessTime.set(pathKey, now);
|
|
377
|
+
|
|
378
|
+
console.log('root--->', pathInfos, value, this._domRender_ref, this._domRender_origin);
|
|
379
|
+
const fullPaths: { path: string; obj: any }[][] = [];
|
|
380
|
+
if (this._domRender_ref.size > 0) {
|
|
381
|
+
this._domRender_ref.forEach((it, key) => {
|
|
382
|
+
if ('_DomRender_isProxy' in key) {
|
|
383
|
+
it.forEach(sit => {
|
|
384
|
+
try {
|
|
385
|
+
const recursiveStartTime = Date.now();
|
|
386
|
+
const concat = pathInfos.concat([[{ path: sit, obj: key }]]);
|
|
387
|
+
const items: { path: string; obj: any }[][] = (key as any)._DomRender_proxy?.root(
|
|
388
|
+
concat,
|
|
389
|
+
value,
|
|
390
|
+
lastDoneExecute
|
|
391
|
+
);
|
|
392
|
+
console.log(`🔄 Recursive root call for ${sit}: ${Date.now() - recursiveStartTime}ms`);
|
|
393
|
+
|
|
394
|
+
fullPaths.push(items.flat());
|
|
395
|
+
// fullPaths.push({path: items.map(it=>it.path).join(','), obj: this._domRender_proxy});
|
|
396
|
+
// fullPaths.push({path: items.map(it=>it.path).join(','), obj: this._domRender_proxy});
|
|
397
|
+
} catch (e) {
|
|
398
|
+
// 오브젝트들 없어졌을수도있다 Destroy시점에서 오류나는경우가 있다. 따라서 참조 하는부분 없어져야한다.
|
|
399
|
+
// console.error(e)
|
|
400
|
+
// it.delete(sit);
|
|
401
|
+
}
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
} else {
|
|
406
|
+
const pathProcessStartTime = Date.now();
|
|
407
|
+
// const firstPathStr = paths.slice(1).reverse().join('.');
|
|
408
|
+
const strings = pathInfos.reverse().map(it => it.map(it => it.path).join(','));
|
|
409
|
+
// array같은경우도 키값으로 접근하기때문에 특정 인덱스를 찾아서 그부분만 바꿔줄수 있다.
|
|
410
|
+
const fullPathStr = strings
|
|
411
|
+
.map(it => (isNaN(Number(it)) ? '.' + it : `[${it}]`))
|
|
412
|
+
.join('')
|
|
413
|
+
.slice(1);
|
|
414
|
+
console.log(`🛤️ Path processing time: ${Date.now() - pathProcessStartTime}ms for path: ${fullPathStr}`);
|
|
415
|
+
if (lastDoneExecute) {
|
|
416
|
+
// const firstData = ScriptUtils.evalReturn('this.' + firstPathStr, this._domRender_proxy);
|
|
417
|
+
// console.log('-------', firstPathStr, firstData);
|
|
418
|
+
// if (firstData instanceof Dictionary) {
|
|
419
|
+
// }
|
|
420
|
+
const iterable = this._rawSets.get(fullPathStr);
|
|
421
|
+
// array check
|
|
422
|
+
const front = strings
|
|
423
|
+
.slice(0, strings.length - 1)
|
|
424
|
+
.map(it => (isNaN(Number(it)) ? '.' + it : `[${it}]`))
|
|
425
|
+
.join('');
|
|
426
|
+
const lastPropertyName = strings[strings.length - 1];
|
|
427
|
+
const path = 'this' + front;
|
|
428
|
+
const data = ScriptUtils.evaluateReturn(ObjectUtils.Path.toOptionalChainPath(path), this._domRender_proxy);
|
|
429
|
+
// console.log('root-->', this._rawSets, path, data );
|
|
430
|
+
// console.log('--!!!!', fullPathStr, iterable, data, front, last);
|
|
431
|
+
// 왜여기서 promise를 했을까를 생각해보면......훔.. 변수변경과 화면 뿌려주는걸 동기로하면 성능이 안나오고 비현실적이다. 그래서 promise
|
|
432
|
+
const promiseStartTime = Date.now();
|
|
433
|
+
new Promise<RawSet[]>(async resolve => {
|
|
434
|
+
const promiseInnerStartTime = Date.now();
|
|
435
|
+
let rData: RawSet[] = [];
|
|
436
|
+
const firstPathStr = front.slice(1);
|
|
437
|
+
|
|
438
|
+
// check dictionary
|
|
439
|
+
const dictionaryCheckStartTime = Date.now();
|
|
440
|
+
// console.log('-promise-------', firstPathStr, this)
|
|
441
|
+
const firstTargets = this._rawSets.get(firstPathStr);
|
|
442
|
+
const firstTargetDictionary: RawSet[] = [];
|
|
443
|
+
firstTargets?.forEach(it => {
|
|
444
|
+
// console.log('----forEach---', it);
|
|
445
|
+
const type = (it.point.start as Element)?.getAttribute?.('type');
|
|
446
|
+
if (type === RawSetOperatorType.DR_THIS_PROPERTY) {
|
|
447
|
+
firstTargetDictionary.push(it);
|
|
448
|
+
}
|
|
449
|
+
});
|
|
450
|
+
console.log(`📚 Dictionary check time: ${Date.now() - dictionaryCheckStartTime}ms (${firstTargetDictionary.length} found)`);
|
|
451
|
+
|
|
452
|
+
if (firstTargetDictionary.length > 0) {
|
|
453
|
+
// console.log('ddddddddddd', firstTargetDictionary);
|
|
454
|
+
const rawSets: RawSet[] = [];
|
|
455
|
+
let skip = false;
|
|
456
|
+
firstTargetDictionary.forEach(it => {
|
|
457
|
+
const startElement = it.point.start as Element;
|
|
458
|
+
const keys = startElement.getAttribute(RawSet.DR_HAS_KEYS_OPTIONNAME)?.split(',') ?? [];
|
|
459
|
+
if (value === undefined) {
|
|
460
|
+
const rawSet = it.getHasRawSet(lastPropertyName);
|
|
461
|
+
rawSet?.remove();
|
|
462
|
+
startElement.setAttribute(
|
|
463
|
+
RawSet.DR_HAS_KEYS_OPTIONNAME,
|
|
464
|
+
keys.filter(it => it !== lastPropertyName).join(',')
|
|
465
|
+
);
|
|
466
|
+
}
|
|
467
|
+
if (!keys.includes(lastPropertyName)) {
|
|
468
|
+
const raws = DrThisProperty.append(
|
|
469
|
+
this._domRender_proxy,
|
|
470
|
+
fullPathStr,
|
|
471
|
+
lastPropertyName,
|
|
472
|
+
it,
|
|
473
|
+
this._domRender_config
|
|
474
|
+
);
|
|
475
|
+
if (raws) {
|
|
476
|
+
rawSets.push(...raws);
|
|
477
|
+
}
|
|
478
|
+
} else {
|
|
479
|
+
skip = true;
|
|
480
|
+
}
|
|
481
|
+
});
|
|
482
|
+
if (skip === false || rawSets.length > 0) {
|
|
483
|
+
rData = await this.render(rawSets);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
const renderStartTime = Date.now();
|
|
488
|
+
if (lastPropertyName === 'length' && Array.isArray(data)) {
|
|
489
|
+
const aIterable = this._rawSets.get(firstPathStr);
|
|
490
|
+
if (aIterable) {
|
|
491
|
+
rData = await this.render(Array.from(aIterable));
|
|
492
|
+
}
|
|
493
|
+
} else if (iterable) {
|
|
494
|
+
// console.log('------------',iterable, fullPaths)
|
|
495
|
+
rData = await this.render(Array.from(iterable), fullPathStr);
|
|
496
|
+
}
|
|
497
|
+
console.log(`🎨 Render time: ${Date.now() - renderStartTime}ms (${rData?.length || 0} rawSets)`);
|
|
498
|
+
|
|
499
|
+
// console.log('-----------', this, lastPropertyName );
|
|
500
|
+
// this._targets.forEach(it => {
|
|
501
|
+
// // return;
|
|
502
|
+
// if (it.nodeType === Node.DOCUMENT_FRAGMENT_NODE || it.nodeType === Node.ELEMENT_NODE) {
|
|
503
|
+
// const targets = eventManager.findAttrElements((it as DocumentFragment | Element), this.config);
|
|
504
|
+
// eventManager.changeVar(this._domRender_proxy, targets, `this.${fullPathStr}`, this.config);
|
|
505
|
+
// }
|
|
506
|
+
// });
|
|
507
|
+
|
|
508
|
+
const eventProcessStartTime = Date.now();
|
|
509
|
+
const Node = ((this._domRender_config.window as any).Node)
|
|
510
|
+
this._targets.forEach(it => {
|
|
511
|
+
// return;
|
|
512
|
+
if (it.nodeType === Node.DOCUMENT_FRAGMENT_NODE || it.nodeType === Node.ELEMENT_NODE) {
|
|
513
|
+
const element = it as DocumentFragment | Element;
|
|
514
|
+
const findAttrStartTime = Date.now();
|
|
515
|
+
|
|
516
|
+
let targets;
|
|
517
|
+
let fromCache = false;
|
|
518
|
+
|
|
519
|
+
// 캐시 확인 (Element만 캐시 가능, DocumentFragment는 제외)
|
|
520
|
+
if (element instanceof Element) {
|
|
521
|
+
const cached = DomRenderProxy._globalElementCache.get(element);
|
|
522
|
+
const now = Date.now();
|
|
523
|
+
|
|
524
|
+
if (cached && (now - cached.timestamp) < 100) { // 100ms 캐시
|
|
525
|
+
targets = cached.elements;
|
|
526
|
+
fromCache = true;
|
|
527
|
+
const targetCount = (targets as any)?.size || (targets as any)?.length || 0;
|
|
528
|
+
console.log(`💾 Using cached findAttrElements (${targetCount} elements)`);
|
|
529
|
+
} else {
|
|
530
|
+
targets = this._domRender_config.eventManager.findAttrElements(element, this._domRender_config);
|
|
531
|
+
DomRenderProxy._globalElementCache.set(element, { elements: targets, timestamp: now });
|
|
532
|
+
}
|
|
533
|
+
} else {
|
|
534
|
+
// DocumentFragment는 캐시하지 않음
|
|
535
|
+
targets = this._domRender_config.eventManager.findAttrElements(element, this._domRender_config);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
const targetCount = (targets as any)?.size || (targets as any)?.length || 0;
|
|
539
|
+
if (!fromCache) {
|
|
540
|
+
console.log(`🔍 Fresh findAttrElements time: ${Date.now() - findAttrStartTime}ms (${targetCount} elements)`);
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
const changeVarStartTime = Date.now();
|
|
544
|
+
this._domRender_config.eventManager.changeVar(
|
|
545
|
+
this._domRender_proxy,
|
|
546
|
+
targets,
|
|
547
|
+
`this.${fullPathStr}`,
|
|
548
|
+
this._domRender_config
|
|
549
|
+
);
|
|
550
|
+
console.log(`🔄 changeVar time: ${Date.now() - changeVarStartTime}ms`);
|
|
551
|
+
}
|
|
552
|
+
});
|
|
553
|
+
console.log(`⚡ Event processing time: ${Date.now() - eventProcessStartTime}ms (${this._targets.size} targets)`);
|
|
554
|
+
|
|
555
|
+
console.log(`🔄 Promise inner total time: ${Date.now() - promiseInnerStartTime}ms`);
|
|
556
|
+
|
|
557
|
+
//랜더대상된게있으면
|
|
558
|
+
if (rData?.length > 0 && isOnChildRenderedByProperty(data)) {
|
|
559
|
+
const propertyValue = ObjectUtils.Script.evaluateReturn(`this.${lastPropertyName}`, data);
|
|
560
|
+
data.onChildRenderedByProperty(lastPropertyName, propertyValue);
|
|
561
|
+
// data
|
|
562
|
+
}
|
|
563
|
+
resolve(rData);
|
|
564
|
+
}).then(it => {
|
|
565
|
+
// console.log('DonrenderProxy root RenderDone')
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
fullPaths.push([{ path: fullPathStr, obj: this._domRender_proxy }]);
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
// 처리 완료 마킹
|
|
572
|
+
DomRenderProxy._processingPaths.delete(pathKey);
|
|
573
|
+
|
|
574
|
+
console.log(`🏁 Root method total time: ${Date.now() - rootStartTime}ms`);
|
|
575
|
+
console.log('dddddd', fullPaths.flatMap(it => it).map(it => it.path))
|
|
576
|
+
console.groupEnd();
|
|
577
|
+
return fullPaths;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
public set(target: T, p: string | symbol, value: any, receiver: T): boolean {
|
|
581
|
+
// console.log('set------->', target, p, value, receiver, Date.now())
|
|
582
|
+
// console.log('set------->', p,value)
|
|
583
|
+
// console.log('set------->', target, p, value, receiver, Date.now())
|
|
584
|
+
// try {
|
|
585
|
+
// const isNoProxy = Reflect.getMetadata(DomRenderNoProxyKey, target, p) || Reflect.getMetadata(DomRenderNoProxyKey, Object.getPrototypeOf(obj).constructor);
|
|
586
|
+
// if (isNoProxy) {
|
|
587
|
+
// return obj;
|
|
588
|
+
// }
|
|
589
|
+
// }catch (e) {}
|
|
590
|
+
|
|
591
|
+
// console.log('set-->', p, value, target, receiver, Reflect.getMetadata(DomRenderNoProxyKey, target, p) );
|
|
592
|
+
|
|
593
|
+
if (
|
|
594
|
+
(typeof p === 'string' && p !== '__domrender_components' && excludeGetSetPropertys.includes(p)) ||
|
|
595
|
+
Reflect.getMetadata(DomRenderNoProxyKey, target, p)
|
|
596
|
+
) {
|
|
597
|
+
(target as any)[p] = value;
|
|
598
|
+
return true;
|
|
599
|
+
}
|
|
600
|
+
// const old = (target as any)[p];
|
|
601
|
+
// console.log('set proxy-->', target, p, value, this._rawSets, this._domRender_ref);
|
|
602
|
+
// if (typeof p === 'string' && '__render' === p) {
|
|
603
|
+
// (target as any)[p] = value;
|
|
604
|
+
// return true;
|
|
605
|
+
// }
|
|
606
|
+
// console.log('set--?', p, target, value);
|
|
607
|
+
|
|
608
|
+
if (typeof p === 'string') {
|
|
609
|
+
value = this.proxy(receiver, value, p);
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
// console.log('set typeChecked', (target as any)[p] instanceof ComponentSet, value instanceof ComponentSet);
|
|
613
|
+
// if ((target as any)[p] instanceof ComponentSet) {
|
|
614
|
+
// (target as any)[p]?.obj?.onDrThisUnBind?.();
|
|
615
|
+
// }
|
|
616
|
+
// is ComponentSet
|
|
617
|
+
if (value instanceof ComponentSet && (target as any)[p] instanceof ComponentSet) {
|
|
618
|
+
value.config.beforeComponentSet = (target as any)[p];
|
|
619
|
+
}
|
|
620
|
+
(target as any)[p] = value;
|
|
621
|
+
let fullPathInfo: { path: string; obj: any }[][] = [];
|
|
622
|
+
if (typeof p === 'string') {
|
|
623
|
+
// 배치 처리로 변경
|
|
624
|
+
this.scheduleBatchUpdate(p, value);
|
|
625
|
+
// 즉시 처리가 필요한 경우를 위해 기본 root 호출도 유지 (하지만 배치에서 중복 제거됨)
|
|
626
|
+
fullPathInfo = this.root([[{ path: p, obj: this._domRender_proxy }]], value);
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
// console.log('setRooot', fullPathInfo);
|
|
630
|
+
|
|
631
|
+
//normal attribute 또한 링크랑 같은 증세라서 이렇게 해줘야한다!!
|
|
632
|
+
// const rootDomRenderProxy = this.findRootDomRenderProxy();
|
|
633
|
+
// console.log('set!!!!!!!', fullPathInfo, rootDomRenderProxy)
|
|
634
|
+
// console.log('--------rootDom',fullPathInfo, rootDomRenderProxy, rootDomRenderProxy._domRender_proxy)
|
|
635
|
+
const rootElement = this._domRender_config.rootElement ?? this._domRender_config.window.document;
|
|
636
|
+
DocumentUtils.querySelectorAllByAttributeName(rootElement, EventManager.normalAttrMapAttrName)?.forEach(
|
|
637
|
+
elementInfo => {
|
|
638
|
+
// @ts-ignore
|
|
639
|
+
// const optionalPath = ObjectUtils.Path.toOptionalChainPath(elementInfo.value);
|
|
640
|
+
const targets = new Map<string, NormalAttrDataType>(
|
|
641
|
+
ObjectUtils.Script.evaluateReturn<[string, NormalAttrDataType][]>(elementInfo.value)
|
|
642
|
+
);
|
|
643
|
+
Array.from(targets.entries())
|
|
644
|
+
.filter(isDefined)
|
|
645
|
+
.flatMap(([key, valueScript]) => {
|
|
646
|
+
return fullPathInfo
|
|
647
|
+
.flat()
|
|
648
|
+
.filter(it => valueScript.variablePaths?.some(vit => vit.inner.includes(`this.${it.path}`)))
|
|
649
|
+
.flatMap(it => ({ key, valueScript: valueScript, pathInfo: it }));
|
|
650
|
+
})
|
|
651
|
+
.forEach(it => {
|
|
652
|
+
// const optionalPaths = it.valueScript.variablePaths.map(it => ObjectUtils.Path.toOptionalChainPath(it))
|
|
653
|
+
const variablePaths = it.valueScript.variablePaths;
|
|
654
|
+
let targetScript = it.valueScript.originalAttrValue;
|
|
655
|
+
let script: string;
|
|
656
|
+
if (it.valueScript.isStringTemplate) {
|
|
657
|
+
variablePaths.forEach(it => {
|
|
658
|
+
let r = ObjectUtils.Path.toOptionalChainPath(it.inner);
|
|
659
|
+
targetScript = targetScript.replaceAll(it.origin, `\${${r}}`);
|
|
660
|
+
})
|
|
661
|
+
script = '`' + targetScript + '`';
|
|
662
|
+
} else {
|
|
663
|
+
variablePaths.forEach(it => {
|
|
664
|
+
let r = ObjectUtils.Path.toOptionalChainPath(it.inner);
|
|
665
|
+
targetScript = targetScript.replaceAll(it.origin, `${r}`);
|
|
666
|
+
})
|
|
667
|
+
script = targetScript;
|
|
668
|
+
}
|
|
669
|
+
// variablePaths.forEach(it => {
|
|
670
|
+
// let r = ObjectUtils.Path.toOptionalChainPath(it.inner);
|
|
671
|
+
// targetScript = targetScript.replaceAll(it.origin,`\${${r}}`);
|
|
672
|
+
// })
|
|
673
|
+
const value1 = ObjectUtils.Script.evaluateReturn(script, it.pathInfo.obj);
|
|
674
|
+
// console.log('proxy set!Attribut======', it.key, value1)
|
|
675
|
+
if (value1 === null) {
|
|
676
|
+
elementInfo.element.removeAttribute(it.key);
|
|
677
|
+
elementInfo.element[it.key] = null;
|
|
678
|
+
} else {
|
|
679
|
+
elementInfo.element.setAttribute(it.key, value1);
|
|
680
|
+
elementInfo.element[it.key] = value1;
|
|
681
|
+
}
|
|
682
|
+
});
|
|
683
|
+
}
|
|
684
|
+
);
|
|
685
|
+
|
|
686
|
+
//여기서 링크 같은거 해줘야함 *-link로 변수값이 변경되면 그걸 참고하고있는 다른것들에도 해줘야한다.
|
|
687
|
+
DocumentUtils.querySelectorAllByAttributeName(rootElement, EventManager.linkTargetMapAttrName)?.forEach(
|
|
688
|
+
elementInfo => {
|
|
689
|
+
// @ts-ignore
|
|
690
|
+
const targets = new Map<string, string>(ScriptUtils.evaluateReturn<[string, string][]>(elementInfo.value));
|
|
691
|
+
|
|
692
|
+
Array.from(targets.entries())
|
|
693
|
+
.filter(([key, value]) => value.trim())
|
|
694
|
+
.filter(isDefined)
|
|
695
|
+
.flatMap(([key, valueScript]) => {
|
|
696
|
+
return fullPathInfo
|
|
697
|
+
.flat()
|
|
698
|
+
.filter(it => valueScript.includes(`this.${it.path}`))
|
|
699
|
+
.flatMap(it => ({ key, valueScript: valueScript, pathInfo: it }));
|
|
700
|
+
})
|
|
701
|
+
.forEach(info => {
|
|
702
|
+
const value1 = ScriptUtils.evaluateReturn(info.valueScript, info.pathInfo.obj);
|
|
703
|
+
const applyAttributeName = EventManager.linkAttrs.find(it => it.name === info.key);
|
|
704
|
+
if (applyAttributeName) {
|
|
705
|
+
if (value1 === null) {
|
|
706
|
+
elementInfo.element.removeAttribute(applyAttributeName.property);
|
|
707
|
+
} else {
|
|
708
|
+
// console.log('ppppppppppppppppppppppp', applyAttributeName, elementInfo)
|
|
709
|
+
elementInfo.element.setAttribute(applyAttributeName.property, value1);
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
});
|
|
713
|
+
|
|
714
|
+
Array.from(targets.entries())
|
|
715
|
+
.filter(([key, value]) => value.trim())
|
|
716
|
+
.filter(isDefined)
|
|
717
|
+
.flatMap(([key, valueScript]) => {
|
|
718
|
+
return fullPathInfo
|
|
719
|
+
.flat()
|
|
720
|
+
.filter(it => valueScript.includes(`this.${it.path}`))
|
|
721
|
+
.flatMap(it => ({ key, valueScript: valueScript, pathInfo: it }));
|
|
722
|
+
})
|
|
723
|
+
.forEach(info => {
|
|
724
|
+
const linkInfo = EventManager.linkAttrs.find(it => it.name === info.key);
|
|
725
|
+
if (linkInfo) {
|
|
726
|
+
elementInfo.element[linkInfo.property] = value;
|
|
727
|
+
}
|
|
728
|
+
});
|
|
729
|
+
}
|
|
730
|
+
);
|
|
731
|
+
|
|
732
|
+
// console.log('---end',receiver);
|
|
733
|
+
if (
|
|
734
|
+
'onBeforeReturnSet' in receiver &&
|
|
735
|
+
typeof p === 'string' &&
|
|
736
|
+
!(this._domRender_config.proxyExcludeOnBeforeReturnSets ?? []).concat(excludeGetSetPropertys).includes(p)
|
|
737
|
+
) {
|
|
738
|
+
if (isOnBeforeReturnSet(receiver)) {
|
|
739
|
+
receiver.onBeforeReturnSet?.(
|
|
740
|
+
p,
|
|
741
|
+
value,
|
|
742
|
+
fullPathInfo.map(it => it.map(it => it.path).join())
|
|
743
|
+
);
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
return true;
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
get(target: T, p: string | symbol, receiver: any): any {
|
|
750
|
+
// console.log('get-->', target, p, receiver);
|
|
751
|
+
if (p === '_DomRender_origin' || p === '_domRender_origin') {
|
|
752
|
+
return this._domRender_origin;
|
|
753
|
+
} else if (p === '_DomRender_ref' || p === '_domRender_ref') {
|
|
754
|
+
return this._domRender_ref;
|
|
755
|
+
} else if (p === '_DomRender_config' || p === '_domRender_config') {
|
|
756
|
+
return this._domRender_config;
|
|
757
|
+
} else if (p === '_DomRender_proxy' || p === '_domRender_proxy') {
|
|
758
|
+
return this;
|
|
759
|
+
} else {
|
|
760
|
+
// Date라던지 이런놈들은-_-프록시가 이상하게 동작해서
|
|
761
|
+
// console.log('--->', p, target, target.bind, 'bind' in target)
|
|
762
|
+
// if ((p in target) && ('bind' in target)) {
|
|
763
|
+
// try{
|
|
764
|
+
// return (target as any)[p].bind(target);
|
|
765
|
+
// }catch (e) {
|
|
766
|
+
// console.error(e)
|
|
767
|
+
// }
|
|
768
|
+
// } else {
|
|
769
|
+
// return (target as any)[p]
|
|
770
|
+
// }
|
|
771
|
+
// return (p in target) ? (target as any)[p].bind(target) : (target as any)[p]
|
|
772
|
+
// console.log('-->', p, Object.prototype.toString.call((target as any)[p]), (target as any)[p])
|
|
773
|
+
// return (target as any)[p]
|
|
774
|
+
let it = (target as any)[p];
|
|
775
|
+
if (
|
|
776
|
+
it &&
|
|
777
|
+
typeof it === 'object' &&
|
|
778
|
+
'_DomRender_isProxy' in it &&
|
|
779
|
+
Object.prototype.toString.call(it._DomRender_origin) === '[object Date]'
|
|
780
|
+
) {
|
|
781
|
+
it = it._DomRender_origin;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
if (
|
|
785
|
+
'onBeforeReturnGet' in receiver &&
|
|
786
|
+
typeof p === 'string' &&
|
|
787
|
+
!(this._domRender_config.proxyExcludeOnBeforeReturnGets ?? []).concat(excludeGetSetPropertys).includes(p)
|
|
788
|
+
) {
|
|
789
|
+
(receiver as any)?.onBeforeReturnGet?.(
|
|
790
|
+
p,
|
|
791
|
+
it,
|
|
792
|
+
this.root([[{ path: p, obj: this._domRender_proxy }]], it, false)
|
|
793
|
+
);
|
|
794
|
+
}
|
|
795
|
+
return it;
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
deleteProperty(target: T, p: string | symbol): boolean {
|
|
800
|
+
delete (target as any)[p];
|
|
801
|
+
if (typeof p === 'string') {
|
|
802
|
+
this.root([[{ path: p, obj: this._domRender_proxy }]]);
|
|
803
|
+
}
|
|
804
|
+
return true;
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
has(target: T, p: string | symbol): boolean {
|
|
808
|
+
return p === '_DomRender_isProxy' || p in target;
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
proxy(parentProxy: T, obj: T | any, p: string) {
|
|
812
|
+
try {
|
|
813
|
+
// const isNoProxy = Reflect.getMetadata(DomRenderNoProxyKey, obj, p) || Reflect.getMetadata(DomRenderNoProxyKey, Object.getPrototypeOf(obj).constructor);
|
|
814
|
+
const isObject = typeof obj === 'object';
|
|
815
|
+
const isNoProxy = isObject && isDomRenderNoProxy(obj, p);
|
|
816
|
+
const isExclude = this._domRender_config.proxyExcludeTyps?.some(it => obj instanceof it) ?? false;
|
|
817
|
+
const isFinal = isObject && DomRenderProxy.isFinal(obj);
|
|
818
|
+
const isFrozen = Object.isFrozen(obj);
|
|
819
|
+
const isShield = obj instanceof Shield;
|
|
820
|
+
if (
|
|
821
|
+
obj === undefined ||
|
|
822
|
+
obj === null ||
|
|
823
|
+
isNoProxy ||
|
|
824
|
+
isExclude ||
|
|
825
|
+
ValidUtils.isNullOrUndefined(obj) ||
|
|
826
|
+
!isObject ||
|
|
827
|
+
isFinal ||
|
|
828
|
+
isFrozen ||
|
|
829
|
+
isShield
|
|
830
|
+
) {
|
|
831
|
+
return obj;
|
|
832
|
+
}
|
|
833
|
+
} catch (e) { }
|
|
834
|
+
|
|
835
|
+
/*
|
|
836
|
+
const proxyTarget = (this._domRender_config.proxyExcludeTyps?.filter(it => obj instanceof it) ?? []).length <= 0;
|
|
837
|
+
if (proxyTarget && obj !== undefined && obj !== null && typeof obj === 'object' && !('_DomRender_isProxy' in obj) && !DomRenderProxy.isFinal(obj) && !Object.isFrozen(obj) && !(obj instanceof Shield)) {
|
|
838
|
+
const domRender = new DomRenderProxy(obj, undefined, this._domRender_config);
|
|
839
|
+
domRender.addRef(parentProxy, p);
|
|
840
|
+
const proxy = new Proxy(obj, domRender);
|
|
841
|
+
domRender.run(proxy);
|
|
842
|
+
return proxy;
|
|
843
|
+
}
|
|
844
|
+
if (proxyTarget && obj !== undefined && obj !== null && typeof obj === 'object' && ('_DomRender_isProxy' in obj) && !DomRenderProxy.isFinal(obj) && !Object.isFrozen(obj) && !(obj instanceof Shield)) {
|
|
845
|
+
const d = (obj as any)._DomRender_proxy as DomRenderProxy<T>;
|
|
846
|
+
d.addRef(this._domRender_proxy!, p);
|
|
847
|
+
return obj;
|
|
848
|
+
} else {
|
|
849
|
+
return obj;
|
|
850
|
+
}
|
|
851
|
+
*/
|
|
852
|
+
if (!isWrapProxyDomRenderProxy(obj)) {
|
|
853
|
+
const domRender = new DomRenderProxy(obj, undefined, this._domRender_config);
|
|
854
|
+
domRender.addRef(parentProxy, p);
|
|
855
|
+
const proxy = new Proxy(obj, domRender);
|
|
856
|
+
domRender.run(proxy);
|
|
857
|
+
return proxy;
|
|
858
|
+
}
|
|
859
|
+
if (isWrapProxyDomRenderProxy(obj)) {
|
|
860
|
+
const d = (obj as any)._DomRender_proxy as DomRenderProxy<T>;
|
|
861
|
+
d.addRef(this._domRender_proxy!, p);
|
|
862
|
+
return obj;
|
|
863
|
+
} else {
|
|
864
|
+
return obj;
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
public addRef(parent: object, path: string) {
|
|
869
|
+
if (!this._domRender_ref.get(parent)) {
|
|
870
|
+
this._domRender_ref.set(parent, new Set<string>());
|
|
871
|
+
}
|
|
872
|
+
this._domRender_ref.get(parent)?.add(path);
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
public addRawSetAndRender(path: string, rawSet: RawSet) {
|
|
876
|
+
this.addRawSet(path, rawSet);
|
|
877
|
+
this.render([rawSet]);
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
public addRawSet(path: string, rawSet: RawSet) {
|
|
881
|
+
// console.log('addRawSet--> path:', path, 'rawSet:', rawSet)
|
|
882
|
+
if (!this._rawSets.get(path)) {
|
|
883
|
+
this._rawSets.set(path, new Set<RawSet>());
|
|
884
|
+
}
|
|
885
|
+
this._rawSets.get(path)?.add(rawSet);
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
// public removeRawSet(...raws: RawSet[]) {
|
|
889
|
+
// this._rawSets.forEach(it => {
|
|
890
|
+
// raws.forEach(sit => it.delete(sit));
|
|
891
|
+
// })
|
|
892
|
+
// this.garbageRawSet();
|
|
893
|
+
// }
|
|
894
|
+
|
|
895
|
+
public removeRawSet(...raws: RawSet[]) {
|
|
896
|
+
this._rawSets.forEach(it => {
|
|
897
|
+
it.forEach(sit => {
|
|
898
|
+
if (!sit.isConnected) {
|
|
899
|
+
it.delete(sit);
|
|
900
|
+
} else if (raws.includes(sit)) {
|
|
901
|
+
it.delete(sit);
|
|
902
|
+
}
|
|
903
|
+
});
|
|
904
|
+
});
|
|
905
|
+
this.targetGarbageRawSet();
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
private targetGarbageRawSet() {
|
|
909
|
+
this._targets.forEach(it => {
|
|
910
|
+
if (!it.isConnected) {
|
|
911
|
+
this._targets.delete(it);
|
|
912
|
+
}
|
|
913
|
+
});
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
// 배치 처리 메서드들
|
|
917
|
+
private scheduleBatchUpdate(path: string, value: any) {
|
|
918
|
+
const now = Date.now();
|
|
919
|
+
const existing = DomRenderProxy._pendingUpdates.get(path);
|
|
920
|
+
|
|
921
|
+
if (existing) {
|
|
922
|
+
// 기존 업데이트가 있으면 값과 프록시 목록 업데이트
|
|
923
|
+
existing.value = value;
|
|
924
|
+
existing.timestamp = now;
|
|
925
|
+
existing.proxies.add(this);
|
|
926
|
+
console.log(`📦 Batch: Updated pending update for ${path} (${existing.proxies.size} proxies)`);
|
|
927
|
+
} else {
|
|
928
|
+
// 새로운 업데이트 추가
|
|
929
|
+
DomRenderProxy._pendingUpdates.set(path, {
|
|
930
|
+
value,
|
|
931
|
+
timestamp: now,
|
|
932
|
+
proxies: new Set([this])
|
|
933
|
+
});
|
|
934
|
+
console.log(`📦 Batch: Added new pending update for ${path}`);
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
// 배치 처리 스케줄링
|
|
938
|
+
this.scheduleBatchProcessing();
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
private scheduleBatchProcessing() {
|
|
942
|
+
if (DomRenderProxy._batchUpdateScheduled) {
|
|
943
|
+
return; // 이미 스케줄됨
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
DomRenderProxy._batchUpdateScheduled = true;
|
|
947
|
+
|
|
948
|
+
// 기존 타임아웃 클리어
|
|
949
|
+
if (DomRenderProxy._batchTimeout) {
|
|
950
|
+
clearTimeout(DomRenderProxy._batchTimeout);
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
// 짧은 지연 후 배치 처리 (마이크로태스크 큐 사용)
|
|
954
|
+
DomRenderProxy._batchTimeout = setTimeout(() => {
|
|
955
|
+
this.processBatchUpdates();
|
|
956
|
+
}, 0);
|
|
957
|
+
|
|
958
|
+
console.log(`⏰ Batch processing scheduled (${DomRenderProxy._pendingUpdates.size} pending)`);
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
private processBatchUpdates() {
|
|
962
|
+
const batchStartTime = Date.now();
|
|
963
|
+
const updateCount = DomRenderProxy._pendingUpdates.size;
|
|
964
|
+
|
|
965
|
+
console.group(`🚀 Processing batch updates (${updateCount} items)`);
|
|
966
|
+
|
|
967
|
+
try {
|
|
968
|
+
// 모든 대기 중인 업데이트 처리
|
|
969
|
+
DomRenderProxy._pendingUpdates.forEach((updateInfo, path) => {
|
|
970
|
+
const updateStartTime = Date.now();
|
|
971
|
+
|
|
972
|
+
// 각 프록시에서 root 호출 (중복 방지 로직이 적용됨)
|
|
973
|
+
updateInfo.proxies.forEach(proxy => {
|
|
974
|
+
try {
|
|
975
|
+
proxy.root([[{ path, obj: proxy._domRender_proxy }]], updateInfo.value);
|
|
976
|
+
} catch (error) {
|
|
977
|
+
console.error(`❌ Batch update error for ${path}:`, error);
|
|
978
|
+
}
|
|
979
|
+
});
|
|
980
|
+
|
|
981
|
+
console.log(`✅ Batch processed ${path}: ${Date.now() - updateStartTime}ms (${updateInfo.proxies.size} proxies)`);
|
|
982
|
+
});
|
|
983
|
+
|
|
984
|
+
// 대기 목록 클리어
|
|
985
|
+
DomRenderProxy._pendingUpdates.clear();
|
|
986
|
+
|
|
987
|
+
} finally {
|
|
988
|
+
// 스케줄링 플래그 리셋
|
|
989
|
+
DomRenderProxy._batchUpdateScheduled = false;
|
|
990
|
+
DomRenderProxy._batchTimeout = null;
|
|
991
|
+
|
|
992
|
+
console.log(`🏁 Batch processing completed: ${Date.now() - batchStartTime}ms`);
|
|
993
|
+
console.groupEnd();
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
private garbageRawSet() {
|
|
998
|
+
this._targets.forEach(it => {
|
|
999
|
+
if (!it.isConnected) {
|
|
1000
|
+
this._targets.delete(it);
|
|
1001
|
+
}
|
|
1002
|
+
});
|
|
1003
|
+
|
|
1004
|
+
this._rawSets.forEach(it => {
|
|
1005
|
+
it.forEach(sit => {
|
|
1006
|
+
if (!sit.isConnected) {
|
|
1007
|
+
it.delete(sit);
|
|
1008
|
+
}
|
|
1009
|
+
});
|
|
1010
|
+
});
|
|
1011
|
+
|
|
1012
|
+
// 캐시 정리: 5초 이상 된 항목 제거
|
|
1013
|
+
const now = Date.now();
|
|
1014
|
+
DomRenderProxy._lastProcessTime.forEach((time, key) => {
|
|
1015
|
+
if (now - time > 5000) {
|
|
1016
|
+
DomRenderProxy._lastProcessTime.delete(key);
|
|
1017
|
+
}
|
|
1018
|
+
});
|
|
1019
|
+
|
|
1020
|
+
// 배치 처리 정리: 10초 이상 된 대기 업데이트 제거
|
|
1021
|
+
DomRenderProxy._pendingUpdates.forEach((updateInfo, key) => {
|
|
1022
|
+
if (now - updateInfo.timestamp > 10000) {
|
|
1023
|
+
console.log(`🧹 Cleaning old batch update: ${key}`);
|
|
1024
|
+
DomRenderProxy._pendingUpdates.delete(key);
|
|
1025
|
+
}
|
|
1026
|
+
});
|
|
1027
|
+
|
|
1028
|
+
// DOM 캐시 정리는 WeakMap이므로 자동으로 가비지 컬렉션됨
|
|
1029
|
+
// 하지만 명시적으로 오래된 캐시 정리 (WeakMap은 직접 순회 불가능하므로 별도 관리 필요시에만)
|
|
1030
|
+
}
|
|
1031
|
+
}
|