Chrome扩展:避免JavaScript重复注入的方案对比及问题排查
防止Chrome扩展内容脚本重复注入的最佳实践
我的Chrome扩展通过后台脚本执行以下代码注入injected.js:
chrome.scripting.executeScript({ target: {tabId: tab.id}, files: ['content/injected.js'] })
我找到了两种避免重复注入的方案:
方案1:全局标记变量(可正常运行)
基于社区方案实现的injected.js代码:
if (window.contentScriptInjected !== true) { window.contentScriptInjected = true; // 全局作用域标记 const focus_event_listner = () => { chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { if (message.type === "StartTimer") { console.log('injected.js: start timer') } }); console.log(document.title, ": has now been injected") } focus_event_listner() } else { console.log(document.title, ": was already injected") }
方案2:检查函数定义(无法正常运行)
尝试用typeof检查函数的实现,代码无法正常工作:
if (typeof focus_event_listner === 'undefined') { const focus_event_listner = () => { chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { if (message.type === "StartTimer") { console.log('injected.js: start timer') } }); console.log(document.title, ": has now been injected") } focus_event_listner() } else { console.log(document.title, ": was already injected") }
问题解答
哪种方案更适合防止JavaScript重复注入?
方案1是更稳妥的选择。它通过在全局window对象上设置明确的注入标记,这个标记在页面生命周期内始终可被后续注入的脚本读取,能准确判断脚本是否已执行,避免重复初始化监听逻辑、重复添加事件监听等问题。第二种方案存在什么问题?
核心问题出在const声明的变量作用域特性:
const声明的变量属于块级作用域,且没有变量提升。第一次执行脚本时,if条件判断先运行,此时focus_event_listner尚未被声明,条件成立进入代码块。但代码块内用const定义的focus_event_listner仅在该块内有效,脚本执行完毕后变量会被回收,不会暴露到全局作用域。- 当脚本被第二次注入时,
if条件再次检查focus_event_listner的类型,发现全局作用域中依然不存在该变量,条件再次成立,导致核心逻辑被重复执行,完全起不到防重复的作用。
内容的提问来源于stack exchange,提问作者Ani
相关产品推荐
相关产品推荐

