如何在多个Userscript间共享同一库实例以降低资源消耗
让多个Userscript共享同一个库实例的解决方案
核心思路是把库挂载到页面的全局作用域(而非每个脚本的沙箱作用域),并采用单例模式确保只初始化一次。这样所有运行在同一页面的Userscript都能访问同一个库实例。
1. 修改库脚本(lib.js)
将库改成单例模式,挂载到页面全局对象上,同时封装操作接口避免直接暴露内部状态:
// 检查页面全局是否已存在库实例,不存在则创建 if (!window.MySharedLib) { window.MySharedLib = (function() { // 内部私有变量,仅在库实例内可访问 let callbacks = []; // 绑定全局事件(只执行一次) document.addEventListener('click', function(event){ // 模拟CPU密集型运算 for (const callback of callbacks) { callback(); } }); // 对外暴露的公共方法 return { // 添加回调函数 addCallback: function(callback) { callbacks.push(callback); }, // 获取当前回调数量 getCallbackCount: function() { return callbacks.length; } }; })(); }
2. 修改Userscript脚本
在每个Userscript中,获取全局的库实例(兼容有无@grant的情况),然后调用公共方法:
script1.user.js
// @match foo.bar // @require lib.js // 适配有无@grant的场景:有@grant时用unsafeWindow访问页面全局,否则直接用window const sharedLib = typeof unsafeWindow !== 'undefined' ? unsafeWindow.MySharedLib : window.MySharedLib; sharedLib.addCallback(function(){ console.log('Script 1: '+sharedLib.getCallbackCount()+' callback(s) registered'); });
script2.user.js
// @match foo.bar // @require lib.js const sharedLib = typeof unsafeWindow !== 'undefined' ? unsafeWindow.MySharedLib : window.MySharedLib; sharedLib.addCallback(function(){ console.log('Script 2: '+sharedLib.getCallbackCount()+' callback(s) registered'); });
为什么这个方案有效?
- 单例模式:第一个加载的脚本会初始化库并挂载到页面全局
window,后续脚本执行lib.js时,发现全局已存在实例,不会重复初始化。 - 沙箱兼容:当Userscript包含
@grant时,脚本运行在独立沙箱中,自身的window和页面全局window不是同一个,此时需要用unsafeWindow来访问页面全局的库实例;无@grant时,脚本直接在页面全局环境运行,可直接用window获取实例。 - 封装性:通过公共方法操作回调,避免了直接修改全局变量带来的意外风险,代码更健壮。
现在点击页面后,输出会符合预期:
Script 1: 2 callback(s) registered Script 2: 2 callback(s) registered
内容的提问来源于stack exchange,提问作者Aran-Fey
相关产品推荐
相关产品推荐

