27 lines
1.5 KiB
TypeScript
27 lines
1.5 KiB
TypeScript
/**
|
|
* 把节点端口/尺寸变化的测量请求合并给 renderer,避免同一轮重复调用更新。
|
|
* owner token 区分同 ID 的不同挂载实例;卸载实例的迟到失效不能触发后来新实例的测量。
|
|
*/
|
|
/** One renderer store's transient measurement requests. Not model or history state. */
|
|
/** 每个 renderer store 独立创建;默认微任务调度,也可注入测试或宿主 defer。 */
|
|
export function createNodeInternalsBatch(update:(ids:string[])=>void,defer:(flush:()=>void)=>void=queueMicrotask){
|
|
const owners=new Map<symbol,string>(),dirty=new Set<symbol>();let queued=false;
|
|
/** 执行时才解析仍有效的 owner,按节点 ID 去重;先清 dirty 再回调,让重入失效进入下一轮。 */
|
|
function flush(){
|
|
queued=false;const ids=new Set<string>();for(const owner of dirty){const id=owners.get(owner);if(id!==undefined)ids.add(id);}dirty.clear();
|
|
if(ids.size)update([...ids]);
|
|
}
|
|
return Object.freeze({
|
|
/** 每次挂载取得独立租约,即使节点 ID 相同也能单独 dispose。 */
|
|
acquire(id:string){
|
|
const owner=Symbol(id);owners.set(owner,id);
|
|
return Object.freeze({
|
|
/** 仅活跃租约可以变脏,同一批最多安排一次延后 flush。 */
|
|
invalidate(){if(!owners.has(owner))return;dirty.add(owner);if(!queued){queued=true;defer(flush);}},
|
|
/** 卸载同时移除 owner 和其未执行请求;已排微任务可自然执行为空,不取得新实例权限。 */
|
|
dispose(){owners.delete(owner);dirty.delete(owner);},
|
|
});
|
|
},
|
|
});
|
|
}
|