Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/app/service/content/exec_script.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,12 @@ export default class ExecScript {
* @see {@link compileScriptCode}
* @returns
*/
exec() {
public readonly exec = () => {
this.logger.debug("script start");
const sandboxContext = this.sandboxContext;
this.execContext = sandboxContext ? createProxyContext(sandboxContext) : global; // this.$ 只能执行一次
return this.scriptFunc.call(this.execContext, this.named, this.scriptRes.name);
}
};

// 早期启动的脚本,处理GM API
updateEarlyScriptGMInfo(envInfo: GMInfoEnv) {
Expand Down
29 changes: 5 additions & 24 deletions src/app/service/content/script_executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { getStorageName } from "@App/pkg/utils/utils";
import type { EmitEventRequest } from "../service_worker/types";
import ExecScript from "./exec_script";
import type { GMInfoEnv, ScriptFunc, ValueUpdateDataEncoded } from "./types";
import { addStyleSheet, definePropertyListener } from "./utils";
import { addStyleSheet, definePropertyListener, waitBody } from "./utils";
import type { ScriptLoadInfo, TScriptInfo } from "@App/app/repo/scripts";
import { DefinedFlags } from "../service_worker/runtime.consts";
import { pageAddEventListener, pageDispatchEvent } from "@Packages/message/common";
Expand Down Expand Up @@ -132,8 +132,8 @@ export class ScriptExecutor {
execScriptEntry(scriptEntry: ExecScriptEntry) {
const { scriptLoadInfo, scriptFunc, envInfo } = scriptEntry;

const exec = new ExecScript(scriptLoadInfo, "scripting", this.msg, scriptFunc, envInfo);
this.execScriptMap.set(scriptLoadInfo.uuid, exec);
const execScript = new ExecScript(scriptLoadInfo, "scripting", this.msg, scriptFunc, envInfo);
this.execScriptMap.set(scriptLoadInfo.uuid, execScript);
const metadata = scriptLoadInfo.metadata || {};
const resource = scriptLoadInfo.resource;
// 注入css
Expand All @@ -147,32 +147,13 @@ export class ScriptExecutor {
}
if (metadata["run-at"] && metadata["run-at"][0] === "document-body") {
// 等待页面加载完成
this.waitBody(() => {
exec.exec();
});
waitBody(execScript.exec);
} else {
try {
exec.exec();
execScript.exec();
} catch {
// 屏蔽错误,防止脚本报错导致后续脚本无法执行
}
}
}

// 参考了tm的实现
waitBody(callback: () => void) {
if (document.body) {
callback();
return;
}
const listen = () => {
document.removeEventListener("load", listen, false);
document.removeEventListener("DOMNodeInserted", listen, false);
document.removeEventListener("DOMContentLoaded", listen, false);
this.waitBody(callback);
};
document.addEventListener("load", listen, false);
document.addEventListener("DOMNodeInserted", listen, false);
document.addEventListener("DOMContentLoaded", listen, false);
}
}
41 changes: 41 additions & 0 deletions src/app/service/content/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,47 @@ export type CompileScriptCodeResource = {
require: Array<{ url: string; content: string }>;
};

// 参考了tm的实现
export const waitBody = (callback: () => void) => {
// 只读取一次 document,避免重复访问 getter
let doc: Document | null = document;

// body 已存在,直接执行回调
if (doc.body) {
try {
callback();
} catch {
// 屏蔽错误,防止脚本报错导致后续脚本无法执行
}
return;
}

let handler: ((this: Document, ev: Event) => void) | null = function () {
// 通常只需等待 body 就绪
// 兼容少数页面在加载过程中替换 document 的情况
if (this.body || document !== this) {
// 确保只清理一次,防止因页面代码骑劫使移除失败后反复触发
if (handler !== null) {
this.removeEventListener("load", handler, false);
this.removeEventListener("DOMNodeInserted", handler, false);
this.removeEventListener("DOMContentLoaded", handler, false);
handler = null; // 释放引用,便于 GC

// 兼容 document 被替换时重新执行
waitBody(callback);
}
}
};

// 注意:避免使用 EventListenerObject
// 某些页面会 hook 事件 API,导致EventListenerObject的监听器或会失灵
doc.addEventListener("load", handler, false);
doc.addEventListener("DOMNodeInserted", handler, false);
doc.addEventListener("DOMContentLoaded", handler, false);

doc = null; // 释放引用,便于 GC
};

// 根据ScriptRunResource获取require的资源
export function getScriptRequire(scriptRes: ScriptRunResource): CompileScriptCodeResource["require"] {
const resourceArray = new Array<{ url: string; content: string }>();
Expand Down
Loading