Skip to content

Commit 690c4a2

Browse files
authored
♻️ 消息传送的API加错误检查,改用 this.EE.removeAllListeners(eventId); (#833)
1 parent c40822b commit 690c4a2

3 files changed

Lines changed: 51 additions & 56 deletions

File tree

packages/message/custom_event_message.ts

Lines changed: 21 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ export class CustomEventMessage implements Message {
7979
data,
8080
};
8181
this.nativeSend(body);
82-
// EventEmitter3 採用同步事件设计,callback会被马上执行而不像传统javascript架构以下一个macrotask 执行
82+
// EventEmitter3 采用同步事件设计,callback会被马上执行而不像传统javascript架构以下一个macrotask 执行
8383
resolve(new WindowMessageConnect(body.messageId, this.EE, new CustomEventPostMessage(this)));
8484
});
8585
}
@@ -103,21 +103,18 @@ export class CustomEventMessage implements Message {
103103

104104
sendMessage<T = any>(data: TMessage): Promise<T> {
105105
return new Promise((resolve: ((value: T) => void) | null) => {
106+
const messageId = uuidv4();
106107
const body: WindowMessageBody<TMessage> = {
107-
messageId: uuidv4(),
108+
messageId,
108109
type: "sendMessage",
109110
data,
110111
};
111-
const eventId = `response:${body.messageId}`;
112-
let callback: EventEmitter.EventListener<string, any> | null = (body: WindowMessageBody<TMessage>) => {
113-
if (callback !== null) {
114-
this.EE.removeListener(eventId, callback);
115-
resolve!(body.data as T);
116-
callback = null; // 设为 null 提醒JS引擎可以GC
117-
resolve = null;
118-
}
119-
};
120-
this.EE.addListener(eventId, callback);
112+
const eventId = `response:${messageId}`;
113+
this.EE.addListener(eventId, (body: WindowMessageBody<TMessage>) => {
114+
this.EE.removeAllListeners(eventId);
115+
resolve!(body.data as T);
116+
resolve = null; // 设为 null 提醒JS引擎可以GC
117+
});
121118
this.nativeSend(body);
122119
});
123120
}
@@ -126,23 +123,22 @@ export class CustomEventMessage implements Message {
126123
// 与content页的消息通讯实际是同步,此方法不需要经过background
127124
// 但是请注意中间不要有promise
128125
syncSendMessage(data: TMessage): TMessage {
126+
const messageId = uuidv4();
129127
const body: WindowMessageBody<TMessage> = {
130-
messageId: uuidv4(),
128+
messageId,
131129
type: "sendMessage",
132130
data,
133131
};
134-
let ret: TMessage;
135-
const eventId = `response:${body.messageId}`;
136-
let callback: EventEmitter.EventListener<string, any> | null = (body: WindowMessageBody<TMessage>) => {
137-
if (callback !== null) {
138-
this.EE.removeListener(eventId, callback);
139-
ret = body.data!;
140-
callback = null; // 设为 null 提醒JS引擎可以GC
141-
}
142-
};
143-
this.EE.addListener(eventId, callback);
144-
this.nativeSend(body);
145-
return ret!;
132+
let ret: TMessage | undefined | null;
133+
const eventId = `response:${messageId}`;
134+
this.EE.addListener(eventId, (body: WindowMessageBody<TMessage>) => {
135+
ret = body.data;
136+
});
137+
this.nativeSend(body); // 执行后立即返回 ret
138+
this.EE.removeAllListeners(eventId); // 即使没有立即执行也能清除callback
139+
// 如果 data 里含有不正确参数(非 primitive type),可能导致没有返回值
140+
if (!ret) throw new Error("syncSendMessage response failed.");
141+
return ret;
146142
}
147143

148144
relateId = 0;

packages/message/window_message.ts

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -103,21 +103,18 @@ export class WindowMessage implements Message {
103103
// 发送消息 注意不进行回调的内存泄漏
104104
sendMessage<T = any>(data: TMessage): Promise<T> {
105105
return new Promise((resolve: ((value: T) => void) | null) => {
106+
const messageId = uuidv4();
106107
const body: WindowMessageBody<TMessage> = {
107-
messageId: uuidv4(),
108+
messageId,
108109
type: "sendMessage",
109110
data,
110111
};
111-
const eventId = `response:${body.messageId}`;
112-
let callback: EventEmitter.EventListener<string, any> | null = (body: WindowMessageBody<TMessage>) => {
113-
if (callback !== null) {
114-
this.EE.removeListener(eventId, callback!);
115-
resolve!(body.data as T);
116-
callback = null; // 设为 null 提醒JS引擎可以GC
117-
resolve = null;
118-
}
119-
};
120-
this.EE.addListener(eventId, callback);
112+
const eventId = `response:${messageId}`;
113+
this.EE.addListener(eventId, (body: WindowMessageBody<TMessage>) => {
114+
this.EE.removeAllListeners(eventId);
115+
resolve!(body.data as T);
116+
resolve = null; // 设为 null 提醒JS引擎可以GC
117+
});
121118
this.target.postMessage(body, "*");
122119
});
123120
}
@@ -216,21 +213,18 @@ export class ServiceWorkerMessageSend implements MessageSend {
216213
async sendMessage<T = any>(data: TMessage): Promise<T> {
217214
await this.init();
218215
return new Promise((resolve: ((value: T) => void) | null) => {
216+
const messageId = uuidv4();
219217
const body: WindowMessageBody<TMessage> = {
220-
messageId: uuidv4(),
218+
messageId,
221219
type: "sendMessage",
222220
data,
223221
};
224-
const eventId = `response:${body.messageId}`;
225-
let callback: EventEmitter.EventListener<string | symbol, any> | null = (body: WindowMessageBody<TMessage>) => {
226-
if (callback !== null) {
227-
this.EE.removeListener(eventId, callback);
228-
resolve!(body.data as T);
229-
callback = null; // 设为 null 提醒JS引擎可以GC
230-
resolve = null;
231-
}
232-
};
233-
this.EE.addListener(eventId, callback);
222+
const eventId = `response:${messageId}`;
223+
this.EE.addListener(eventId, (body: WindowMessageBody<TMessage>) => {
224+
this.EE.removeAllListeners(eventId);
225+
resolve!(body.data as T);
226+
resolve = null; // 设为 null 提醒JS引擎可以GC
227+
});
234228
this.target!.postMessage(body);
235229
});
236230
}

src/app/service/content/gm_api.ts

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -632,6 +632,7 @@ export default class GMApi extends GM_Base {
632632
@GMContext.API({ alias: "GM.addStyle" })
633633
GM_addStyle(css: string) {
634634
if (!this.message || !this.scriptRes) return;
635+
if (typeof css !== "string") throw new Error("The parameter 'css' of GM_addStyle shall be a string.");
635636
// 与content页的消息通讯实际是同步,此方法不需要经过background
636637
// 这里直接使用同步的方式去处理, 不要有promise
637638
const resp = (<CustomEventMessage>this.message).syncSendMessage({
@@ -655,27 +656,31 @@ export default class GMApi extends GM_Base {
655656
}
656657

657658
@GMContext.API({ alias: "GM.addElement" })
658-
GM_addElement(parentNode: EventTarget | string, tagName: any, attrs?: any) {
659+
GM_addElement(
660+
parentNode: EventTarget | string,
661+
tagName: string | Record<string, string | number | boolean>,
662+
attrs: Record<string, string | number | boolean> = {}
663+
) {
659664
if (!this.message || !this.scriptRes) return;
660665
// 与content页的消息通讯实际是同步,此方法不需要经过background
661666
// 这里直接使用同步的方式去处理, 不要有promise
662-
let parentNodeId: any = parentNode;
663-
if (typeof parentNodeId !== "string") {
664-
const id = (<CustomEventMessage>this.message).sendRelatedTarget(parentNodeId);
667+
let parentNodeId: number | null;
668+
if (typeof parentNode !== "string") {
669+
const id = (<CustomEventMessage>this.message).sendRelatedTarget(parentNode);
665670
parentNodeId = id;
666671
} else {
667672
parentNodeId = null;
673+
attrs = tagName as Record<string, string | number | boolean>;
674+
tagName = parentNode as string;
668675
}
676+
if (typeof tagName !== "string") throw new Error("The parameter 'tagName' of GM_addElement shall be a string.");
677+
if (typeof attrs !== "object") throw new Error("The parameter 'attrs' of GM_addElement shall be an object.");
669678
const resp = (<CustomEventMessage>this.message).syncSendMessage({
670679
action: `${this.prefix}/runtime/gmApi`,
671680
data: {
672681
uuid: this.scriptRes.uuid,
673682
api: "GM_addElement",
674-
params: [
675-
parentNodeId,
676-
typeof parentNode === "string" ? parentNode : tagName,
677-
typeof parentNode === "string" ? tagName : attrs,
678-
],
683+
params: [parentNodeId, tagName, attrs],
679684
},
680685
});
681686
if (resp.code) {

0 commit comments

Comments
 (0)