mirror of
https://github.com/Shu-Ying/noname-shuying.git
synced 2026-10-17 20:59:58 +08:00
整合
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
// Candidate only: attach to fresh, session-owned roots BEFORE scheduling them.
|
||||
const attached = new WeakSet();
|
||||
export function observeFreshEvent(session, event) {
|
||||
if (!event || typeof event.start !== "function" || !event.manager?.eventStack ||
|
||||
event.finished || event.manager.eventStack.includes(event) ||
|
||||
event.parent?.childEvents?.includes(event) || attached.has(event)) {
|
||||
throw new Error("Fresh, unobserved engine event required");
|
||||
}
|
||||
const descriptor = Object.getOwnPropertyDescriptor(event, "start");
|
||||
if (descriptor && !descriptor.configurable) throw new Error("Event start is not configurable");
|
||||
const original = event.start;
|
||||
let resolve, reject;
|
||||
const completion = new Promise((yes, no) => { resolve = yes; reject = no; });
|
||||
session.ownEvent(event, completion);
|
||||
let observed = false;
|
||||
function start(...args) {
|
||||
let result;
|
||||
try { result = Reflect.apply(original, this, args); }
|
||||
catch (error) { reject(error); throw error; }
|
||||
if (!observed) {
|
||||
observed = true;
|
||||
if (!(result instanceof Promise)) {
|
||||
reject(new TypeError("Native engine start promise required"));
|
||||
} else {
|
||||
result.then(() => {
|
||||
if (event.manager.eventStack.includes(event) || event.manager.tempEvent === event) {
|
||||
reject(new Error("Event still active after start completion"));
|
||||
} else resolve();
|
||||
}, reject);
|
||||
}
|
||||
}
|
||||
return result; // Never assimilate event.then(), never proactively start a queue.
|
||||
}
|
||||
Object.defineProperty(event, "start", { configurable: true, writable: true, value: start });
|
||||
attached.add(event);
|
||||
session.ownResource({}, () => {
|
||||
if (event.start === start) {
|
||||
if (descriptor) Object.defineProperty(event, "start", descriptor);
|
||||
else delete event.start;
|
||||
}
|
||||
attached.delete(event);
|
||||
});
|
||||
return completion;
|
||||
}
|
||||
|
||||
// Independent delay entry: releasing it never calls global resume/pause2/over.resolve.
|
||||
export function acquirePauseLease(session, pauseManager) {
|
||||
if (!session.active || typeof pauseManager?.setDelay !== "function") throw new Error("Active session and pause manager required");
|
||||
let unlock;
|
||||
const gate = new Promise(resolve => { unlock = resolve; });
|
||||
const settled = pauseManager.setDelay(gate);
|
||||
let released = false;
|
||||
const lease = Object.freeze({
|
||||
release() { if (!released) { released = true; unlock(); } return settled; },
|
||||
get released() { return released; },
|
||||
});
|
||||
session.ownResource(lease, () => lease.release());
|
||||
return lease;
|
||||
}
|
||||
|
||||
// Call outside tracked event/task bodies. Own pauses must be lifted before drain.
|
||||
export async function stopAndDrain(session, leases = []) {
|
||||
session.requestStop();
|
||||
await Promise.all(leases.map(lease => lease.release()));
|
||||
await session.drain();
|
||||
}
|
||||
|
||||
// Only remove this exact node from the parent recorded at acquisition.
|
||||
export function ownNode(session, node) {
|
||||
const parent = node.parentNode;
|
||||
if (!parent) throw new Error("Attached node required");
|
||||
return session.ownResource(node, () => {
|
||||
if (node.parentNode === parent) parent.removeChild(node);
|
||||
});
|
||||
}
|
||||
export function ownListener(session, target, type, listener, options) {
|
||||
const guarded = session.guard(listener);
|
||||
const capture = typeof options === "boolean" ? options : !!options?.capture;
|
||||
const token = {};
|
||||
session.ownResource(token, () => target.removeEventListener(type, guarded, capture));
|
||||
target.addEventListener(type, guarded, options);
|
||||
return guarded;
|
||||
}
|
||||
Reference in New Issue
Block a user