You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在多个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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:32:48