脚本中卸载脚本如何清理干净

wen 实用脚本 2

本文目录导读:

脚本中卸载脚本如何清理干净

  1. 浏览器用户脚本(Tampermonkey / Greasemonkey 等)
  2. Node.js 模块
  3. 浏览器扩展(Chrome/Firefox)
  4. 通用的清理原则
  5. 如果脚本没有提供清理功能(最坏情况)
  6. 总结:最好的清理是“设计时考虑清理”

在脚本环境中,“卸载脚本”通常指移除脚本加载的全局变量、事件监听、定时器、DOM元素修改等副作用,要“清理干净”,需要根据脚本的类型(如用户脚本、Node.js模块、浏览器扩展等)采取不同的策略,以下是几种常见场景的清理方法:

浏览器用户脚本(Tampermonkey / Greasemonkey 等)

用户脚本通常通过 @grant 声明权限,要完全清理卸载,需要还原脚本所做的所有修改。

脚本内部应提供卸载函数

// ==UserScript==
// @name         My Script
// @grant        GM_addStyle
// @grant        GM_registerMenuCommand
// ==/UserScript==
// 存储所有副作用,便于卸载清理
const cleanups = [];
// 示例1: 添加全局样式
const style = GM_addStyle('.my-script-style { color: red; }');
cleanups.push(() => style.remove());
// 示例2: 添加事件监听
const handler = () => console.log('clicked');
document.addEventListener('click', handler);
cleanups.push(() => document.removeEventListener('click', handler));
// 示例3: 设置定时器
const timer = setInterval(() => {}, 1000);
cleanups.push(() => clearInterval(timer));
// 示例4: 修改DOM(需记录原始状态)
const originalContent = document.body.innerHTML;
cleanups.push(() => { document.body.innerHTML = originalContent; });
// 卸载函数
window.myScriptCleanup = function() {
  cleanups.forEach(fn => fn());
  cleanups.length = 0; // 清空数组
  console.log('Script cleaned up');
};
// 在菜单中添加卸载命令(如果支持)
GM_registerMenuCommand('Uninstall Script', () => {
  window.myScriptCleanup();
});

手动清理:如果脚本没有提供卸载函数,需要手动检查并移除:

  • 检查 document.head 中是否有脚本注入的 <style><link>
  • 移除脚本添加的全局变量(如 window.myScriptData)。
  • 清空定时器(通过 console.log 或开发者工具查看 setInterval 的ID)。
  • 移除事件监听(在开发者工具的 Event Listeners 面板中查找)。

Node.js 模块

Node.js 中卸载模块通常指从 require.cache 中清除,并释放其副作用(如全局变量、定时器、数据库连接等)。

模块内部清理

// my-module.js
let timer;
module.exports = {
  start() {
    timer = setInterval(() => {}, 1000);
  },
  // 提供清理方法
  cleanup() {
    clearInterval(timer);
    // 关闭数据库连接、文件描述符等
    console.log('Module cleaned up');
  }
};

外部强制卸载

// 强制从缓存中删除模块
const modulePath = require.resolve('./my-module.js');
delete require.cache[modulePath];
// 但模块内的定时器仍然存在!需要手动调用清理
const myModule = require('./my-module.js');
myModule.cleanup();

更好的做法:使用 process.on('exit')process.on('SIGINT') 自动清理:

process.on('exit', () => {
  clearInterval(timer);
  // 其他清理
});

浏览器扩展(Chrome/Firefox)

扩展卸载时,浏览器会自动清理大部分副作用(如后台页面、内容脚本),但持久化数据(如 chrome.storage、IndexedDB、Cookies)不会被自动清除。

清理持久化数据

  • 在扩展的 background.js 中添加卸载监听:

    // 监听扩展被卸载(仅 Chrome 支持)
    chrome.runtime.onSuspend.addListener(() => {
    // 清理存储
    chrome.storage.local.clear();
    // 清理 IndexedDB
    indexedDB.deleteDatabase('MyDB');
    // 清理 Cookies(需指定域名)
    chrome.cookies.remove({ url: 'https://example.com', name: 'session' });
    });
  • 或者让用户手动清除:在扩展选项中提供“清除所有数据”按钮。

通用的清理原则

无论哪种脚本,清理都应该遵循以下步骤:

  1. 记录所有副作用:在脚本初始运行时,保存所有被修改的状态、创建的对象、注册的回调。
  2. 提供反函数:每个副作用都对应一个还原操作(如 addEventListenerremoveEventListenersetTimeoutclearTimeout)。
  3. 提供统一的清理接口:如 cleanup()destroy() 或全局变量 __cleanup__
  4. 事件监听器:使用有名字的函数(不要用匿名函数)以便移除。
  5. 定时器:保存所有定时器ID,统一 clearInterval/clearTimeout
  6. DOM修改:如果修改了很多内容,最好在开始时保存一份原始 DOM 快照(document.body.cloneNode(true)),清理时恢复。

如果脚本没有提供清理功能(最坏情况)

  • 对于用户脚本:禁用或卸载该脚本(在Tampermonkey中点击“移除”),然后刷新页面——大部分副作用会随页面重载消失。
  • 对于Node.js:关闭进程(Ctrl+C),所有定时器和监听器都会随进程终止。
  • 对于浏览器扩展:在 chrome://extensions 中移除扩展,刷新所有受影响页面。

最好的清理是“设计时考虑清理”

  • 写脚本时:始终提供 cleanup() 函数,并遵循“副作用记录+反向操作”模式。
  • 卸载时:优先调用脚本提供的清理函数,然后刷新页面或重启进程。
  • 持久数据:需要手动删除存储(存储、数据库、cookies)。

抱歉,评论功能暂时关闭!