Skip to content

Commit fc3c291

Browse files
authored
♻️ 改良代码 - .bind & closure GC (#1211)
* [v1.3] 改良代码 - .bind & closure GC * .bind & closure GC (2)
1 parent 1f60c01 commit fc3c291

File tree

9 files changed

+137
-148
lines changed

9 files changed

+137
-148
lines changed

packages/message/message_queue.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,7 @@ export class MessageQueue implements IMessageQueue {
6969

7070
subscribe<T>(topic: string, handler: (msg: T) => void) {
7171
this.EE.on(topic, handler);
72-
return () => {
73-
this.EE.off(topic, handler);
74-
};
72+
return this.EE.off.bind(this.EE, topic, handler) as () => void;
7573
}
7674

7775
publish<T>(topic: string, message: NonNullable<T>) {

packages/message/server.ts

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -277,18 +277,10 @@ export function forwardMessage(
277277
const fromConnect = fromCon.getConnect();
278278
if (fromConnect) {
279279
connect(senderTo, `${prefix}/${path}`, params).then((toCon: MessageConnect) => {
280-
fromConnect.onMessage((data) => {
281-
toCon.sendMessage(data);
282-
});
283-
toCon.onMessage((data) => {
284-
fromConnect.sendMessage(data);
285-
});
286-
fromConnect.onDisconnect(() => {
287-
toCon.disconnect();
288-
});
289-
toCon.onDisconnect(() => {
290-
fromConnect.disconnect();
291-
});
280+
fromConnect.onMessage(toCon.sendMessage.bind(toCon));
281+
toCon.onMessage(fromConnect.sendMessage.bind(fromConnect));
282+
fromConnect.onDisconnect(toCon.disconnect.bind(toCon));
283+
toCon.onDisconnect(fromConnect.disconnect.bind(fromConnect));
292284
});
293285
} else {
294286
return sendMessage(senderTo, prefix + "/" + path, params);

src/app/cache.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -144,17 +144,19 @@ class Cache extends ExtCache {
144144
return stackAsyncTask(key, () => {
145145
let ret: Awaited<ReturnType<CB>>;
146146
const act = { action: Actions.NONE } as { action?: number; newVal?: T };
147+
const set = (newVal: T) => {
148+
act.action = Actions.SET;
149+
act.newVal = newVal;
150+
};
151+
const del = () => {
152+
act.action = Actions.DEL;
153+
act.newVal = undefined;
154+
};
147155
return this.get<T>(key)
148156
.then((result) => {
149157
const tx = {
150-
set: (newVal: T) => {
151-
act.action = Actions.SET;
152-
act.newVal = newVal;
153-
},
154-
del: () => {
155-
act.action = Actions.DEL;
156-
act.newVal = undefined;
157-
},
158+
set,
159+
del,
158160
};
159161
return callback(result, tx);
160162
})

src/app/service/service_worker/gm_api/gm_api.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -874,10 +874,8 @@ export default class GMApi {
874874
msgConn.sendMessage(msg);
875875
}
876876
});
877-
msgConn.onDisconnect(() => {
878-
// 关闭连接
879-
offscreenCon.disconnect();
880-
});
877+
// 关闭连接
878+
msgConn.onDisconnect(offscreenCon.disconnect.bind(offscreenCon));
881879
}
882880
} catch (e: any) {
883881
throw throwErrorFn(`GM_xmlhttpRequest ERROR: ${e?.message || e || "Unknown Error"}`);

src/pages/options/routes/script/ScriptEditor.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,7 @@ const Editor: React.FC<{
7676
onChange(node.editor.getValue() || "");
7777
});
7878
callbackEditor(node.editor);
79-
return () => {
80-
node.editor.dispose();
81-
};
79+
return node.editor.dispose.bind(node.editor);
8280
}, [node?.editor]);
8381

8482
return <CodeEditor key={id} id={id} ref={ref} className={className} code={code} diffCode="" editable />;

src/pages/store/favicons.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -85,12 +85,10 @@ export const timeoutAbortSignal =
8585
return AbortSignal.timeout(milis);
8686
}
8787
: (milis: number) => {
88-
let controller: AbortController | null = new AbortController();
88+
const controller: AbortController = new AbortController();
8989
const signal = controller.signal;
90-
setTimeout(() => {
91-
controller!.abort(); // 中断请求
92-
controller = null;
93-
}, milis);
90+
// 中断请求
91+
setTimeout(controller.abort.bind(controller), milis);
9492
return signal;
9593
};
9694

src/pkg/config/config.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,7 @@ export class SystemConfig {
9292
callback: (value: SystemConfigValueType<T>, prev: SystemConfigValueType<T> | undefined) => void
9393
) {
9494
this.EE.on(key, callback);
95-
return () => {
96-
this.EE.off(key, callback);
97-
};
95+
return this.EE.off.bind(this.EE, key, callback) as () => void;
9896
}
9997

10098
// 监听配置变更,会使用设置值立即执行一次回调

src/pkg/utils/xhr/bg_gm_xhr.ts

Lines changed: 106 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ export class BgGMXhr {
153153
this.isConnDisconnected = false;
154154
}
155155

156-
onDataReceived(param: { chunk: boolean; type: string; data: any }) {
156+
private readonly onDataReceived = (param: { chunk: boolean; type: string; data: any }) => {
157157
stackAsyncTask(this.taskId, async () => {
158158
if (this.isConnDisconnected) return;
159159
try {
@@ -211,7 +211,7 @@ export class BgGMXhr {
211211
console.error(e);
212212
}
213213
});
214-
}
214+
};
215215

216216
callback(result: BgGMXhrCallbackResult) {
217217
const data = {
@@ -266,7 +266,7 @@ export class BgGMXhr {
266266
let rawData = (details.data = await details.data);
267267

268268
const baseXHR = useFetch
269-
? new FetchXHR(isBufferStream, this.onDataReceived.bind(this), (opts: RequestInit) => {
269+
? new FetchXHR(isBufferStream, this.onDataReceived, (opts: RequestInit) => {
270270
if (redirect) {
271271
opts.redirect = redirect;
272272
}
@@ -283,113 +283,114 @@ export class BgGMXhr {
283283
})
284284
: new XMLHttpRequest();
285285

286-
this.abort = () => {
287-
baseXHR.abort();
288-
};
286+
this.abort = baseXHR.abort.bind(baseXHR);
289287

290288
const url = details.url;
291289
if (details.overrideMimeType) {
292290
baseXHR.overrideMimeType(details.overrideMimeType);
293291
}
294292

295-
let contentType = "";
296-
let responseHeaders: string | null = null;
297-
let finalStateChangeEvent: XHREvent | null = null;
298-
let canTriggerFinalStateChangeEvent = false;
299-
const callback = (evt: XHREvent, err?: Error | string) => {
300-
const xhr = baseXHR;
301-
const eventType = evt.type;
302-
// 对齐 TM 的实现:不处理 readyState 从 0 到 1 和 2 到 3 的 onreadystatechange 事件。
303-
if (useFetch && eventType === "readystatechange" && (xhr.readyState === 1 || xhr.readyState === 3)) {
304-
return;
305-
}
306-
const isProgressEvt = isProgressEvent(evt);
307-
308-
if (eventType === "load") {
309-
canTriggerFinalStateChangeEvent = true;
310-
if (finalStateChangeEvent) callback(finalStateChangeEvent);
311-
} else if (eventType === "readystatechange" && xhr.readyState === 4) {
312-
// readyState4 的readystatechange或会重复,见 https://github.com/violentmonkey/violentmonkey/issues/1862
313-
if (!canTriggerFinalStateChangeEvent) {
314-
finalStateChangeEvent = evt;
293+
{
294+
const localThis = baseXHR;
295+
let contentType = "";
296+
let responseHeaders: string | null = null;
297+
let finalStateChangeEvent: XHREvent | null = null;
298+
let canTriggerFinalStateChangeEvent = false;
299+
const callback = (evt: XHREvent, err?: Error | string) => {
300+
const xhr = localThis;
301+
const eventType = evt.type;
302+
// 对齐 TM 的实现:不处理 readyState 从 0 到 1 和 2 到 3 的 onreadystatechange 事件。
303+
if (useFetch && eventType === "readystatechange" && (xhr.readyState === 1 || xhr.readyState === 3)) {
315304
return;
316305
}
317-
}
318-
canTriggerFinalStateChangeEvent = false;
319-
finalStateChangeEvent = null;
320-
321-
// contentType 和 responseHeaders 只读一次
322-
contentType = contentType || xhr.getResponseHeader("Content-Type") || "";
323-
if (contentType && !responseHeaders) {
324-
// TM兼容: 原生xhr有 \r\n 在尾,但TM的GMXhr没有;同时除去冒号后面的空白
325-
responseHeaders = normalizeResponseHeaders(xhr.getAllResponseHeaders());
326-
}
327-
if (!(xhr instanceof FetchXHR)) {
328-
const response = xhr.response;
329-
if (xhr.readyState === 4 && eventType === "readystatechange") {
330-
if (xhrResponseType === "" || xhrResponseType === "text") {
331-
this.onDataReceived({ chunk: false, type: "text", data: xhr.responseText });
332-
} else if (xhrResponseType === "arraybuffer" && response instanceof ArrayBuffer) {
333-
this.onDataReceived({ chunk: false, type: "arraybuffer", data: response });
306+
const isProgressEvt = isProgressEvent(evt);
307+
308+
if (eventType === "load") {
309+
canTriggerFinalStateChangeEvent = true;
310+
if (finalStateChangeEvent) callback(finalStateChangeEvent);
311+
} else if (eventType === "readystatechange" && xhr.readyState === 4) {
312+
// readyState4 的readystatechange或会重复,见 https://github.com/violentmonkey/violentmonkey/issues/1862
313+
if (!canTriggerFinalStateChangeEvent) {
314+
finalStateChangeEvent = evt;
315+
return;
316+
}
317+
}
318+
canTriggerFinalStateChangeEvent = false;
319+
finalStateChangeEvent = null;
320+
321+
// contentType 和 responseHeaders 只读一次
322+
contentType = contentType || xhr.getResponseHeader("Content-Type") || "";
323+
if (contentType && !responseHeaders) {
324+
// TM兼容: 原生xhr有 \r\n 在尾,但TM的GMXhr没有;同时除去冒号后面的空白
325+
responseHeaders = normalizeResponseHeaders(xhr.getAllResponseHeaders());
326+
}
327+
if (!(xhr instanceof FetchXHR)) {
328+
const response = xhr.response;
329+
if (xhr.readyState === 4 && eventType === "readystatechange") {
330+
if (xhrResponseType === "" || xhrResponseType === "text") {
331+
this.onDataReceived({ chunk: false, type: "text", data: xhr.responseText });
332+
} else if (xhrResponseType === "arraybuffer" && response instanceof ArrayBuffer) {
333+
this.onDataReceived({ chunk: false, type: "arraybuffer", data: response });
334+
}
334335
}
335336
}
336-
}
337337

338-
const result: BgGMXhrCallbackResult = {
339-
/*
340-
341-
342-
finalUrl: string; // sw handle
343-
readyState: 0 | 4 | 2 | 3 | 1;
344-
status: number;
345-
statusText: string;
346-
responseHeaders: string;
347-
error?: string; // sw handle?
348-
349-
useFetch: boolean,
350-
eventType: string,
351-
ok: boolean,
352-
contentType: string,
353-
error: undefined | string,
354-
355-
*/
356-
357-
useFetch: useFetch,
358-
eventType: eventType,
359-
ok: xhr.status >= 200 && xhr.status < 300,
360-
contentType,
361-
// Always
362-
readyState: xhr.readyState as GMTypes.ReadyState,
363-
// After response headers
364-
status: xhr.status,
365-
statusText: xhr.statusText,
366-
// After load
367-
// response: response,
368-
// responseText: responseText,
369-
// responseXML: responseXML,
370-
// After headers received
371-
responseHeaders: responseHeaders,
372-
responseURL: xhr.responseURL,
373-
// How to get the error message in native XHR ?
374-
error: eventType !== "error" ? undefined : (err as Error)?.message || err || "Unknown Error",
375-
} satisfies BgGMXhrCallbackResult;
376-
377-
if (isProgressEvt) {
378-
result.total = evt.total;
379-
result.loaded = evt.loaded;
380-
result.lengthComputable = evt.lengthComputable;
381-
}
338+
const result: BgGMXhrCallbackResult = {
339+
/*
340+
341+
342+
finalUrl: string; // sw handle
343+
readyState: 0 | 4 | 2 | 3 | 1;
344+
status: number;
345+
statusText: string;
346+
responseHeaders: string;
347+
error?: string; // sw handle?
348+
349+
useFetch: boolean,
350+
eventType: string,
351+
ok: boolean,
352+
contentType: string,
353+
error: undefined | string,
354+
355+
*/
356+
357+
useFetch: useFetch,
358+
eventType: eventType,
359+
ok: xhr.status >= 200 && xhr.status < 300,
360+
contentType,
361+
// Always
362+
readyState: xhr.readyState as GMTypes.ReadyState,
363+
// After response headers
364+
status: xhr.status,
365+
statusText: xhr.statusText,
366+
// After load
367+
// response: response,
368+
// responseText: responseText,
369+
// responseXML: responseXML,
370+
// After headers received
371+
responseHeaders: responseHeaders,
372+
responseURL: xhr.responseURL,
373+
// How to get the error message in native XHR ?
374+
error: eventType !== "error" ? undefined : (err as Error)?.message || err || "Unknown Error",
375+
} satisfies BgGMXhrCallbackResult;
376+
377+
if (isProgressEvt) {
378+
result.total = evt.total;
379+
result.loaded = evt.loaded;
380+
result.lengthComputable = evt.lengthComputable;
381+
}
382382

383-
this.callback(result);
384-
};
385-
baseXHR.onabort = callback;
386-
baseXHR.onloadstart = callback;
387-
baseXHR.onload = callback;
388-
baseXHR.onerror = callback;
389-
baseXHR.onprogress = callback;
390-
baseXHR.ontimeout = callback;
391-
baseXHR.onreadystatechange = callback;
392-
baseXHR.onloadend = callback;
383+
this.callback(result);
384+
};
385+
baseXHR.onabort = callback;
386+
baseXHR.onloadstart = callback;
387+
baseXHR.onload = callback;
388+
baseXHR.onerror = callback;
389+
baseXHR.onprogress = callback;
390+
baseXHR.ontimeout = callback;
391+
baseXHR.onreadystatechange = callback;
392+
baseXHR.onloadend = callback;
393+
}
393394

394395
baseXHR.open(details.method ?? "GET", url, true, details.user, details.password);
395396

@@ -482,15 +483,17 @@ export class BgGMXhr {
482483
await prepareXHR();
483484
}
484485

486+
private readonly handleDisconnect = () => {
487+
this.isConnDisconnected = true;
488+
this.abort?.();
489+
// console.warn("msgConn.onDisconnect");
490+
};
491+
485492
do() {
486493
this.bgXhrRequestFn().catch((e: any) => {
487494
this.abort?.();
488495
console.error(e);
489496
});
490-
this.msgConn.onDisconnect(() => {
491-
this.isConnDisconnected = true;
492-
this.abort?.();
493-
// console.warn("msgConn.onDisconnect");
494-
});
497+
this.msgConn.onDisconnect(this.handleDisconnect);
495498
}
496499
}

0 commit comments

Comments
 (0)