javascript - 如何在加载之前可靠地删除脚本标签?
问题描述
我创建了一个突变观察者来在某些条件下删除(阻止)脚本。
有几种 SO 解决方案表明它可以工作。例如:https ://stackoverflow.com/a/65453574/4688612
但它不适用于我的情况<script src="https://www.googletagmanager.com/gtag/js?id=UA-12345678-9"></script>
出于某种原因,对 googletagmanager.com 的网络调用仍然会在每次页面加载时发生。
Google Chrome 和 Firefox 都加载脚本。
现在我不确定使用突变观察者方法是否根本不可靠或错误,或者它是否是我代码中的错误。
有没有可靠的解决方案?
这是我的代码。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="shortcut icon" href="#">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"
integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous">
</script>
<script>
const observer = new MutationObserver( (mutations) =>{
mutations.forEach(({addedNodes}) => {
[...addedNodes]
.forEach(node => {
$(node).remove()
});
});
})
observer.observe(document.head, { childList: true });
</script>
<script src="https://www.googletagmanager.com/gtag/js?id=UA-12345678-9"></script>
</head>
<body></body>
</html>
```
解决方案
应该改为添加脚本
正如评论中所讨论的,用观察者删除脚本是不可靠的。
- 浏览器可以在知道 URL 后立即预取文件,与
src
呈现的 HTML 标记无关 - 浏览器不必诚实或完美。它可能会预取文件而不在开发人员工具中(还)列出它。
- 并非所有浏览器的所有版本都实现了变异观察者:参见caniuse MutationObserver。这可能会吸引人们故意使用旧版浏览器并抱怨。因此,这不是满足法律要求的可靠方式。
相反,应在需要时添加脚本:
(function(p,a,n,t,s){
t=p.createElement(a),s=p.getElementsByTagName(a)[0];
t.async=1;t.src=n;s.parentNode.insertBefore(t,s)
})(document,'script','https://www.googletagmanager.com/gtag/js?id=UA-12345678-9');
在本地测试你的观察者
下面将说明这里可能出现的问题。
我创建了一个 index.html 和你的一样,但使用本地加载的脚本test.js
。我还添加console.log(node);
了您的观察者。
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MutationObserver test</title>
<link rel="shortcut icon" href="#">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"
integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
<script>
const observer = new MutationObserver( (mutations) =>{
mutations.forEach(({addedNodes}) => {
[...addedNodes]
.forEach(node => {
console.log(node);
$(node).remove()
});
});
});
observer.observe(document.head, { childList: true });
</script>
<script src="test.js"></script>
</head>
<body></body>
</html>
test.js
console.log("I got loaded before you could remove me.");
这将导致以下控制台日志:
index.html:21 " "
index.html:21 <script src="test.js"></script>
index.html:21 " "
所以观察者正在工作,因为它还捕获只有空白字符的空节点。
但是在网络选项卡test.js
中仍然列为已加载:
Name Status Type Initiator Size Time
index.html Finished document Other 972 B 1 ms
test.js Finished script index.html 56 B 3 ms
jquery-3... 200 script index.html 31.0 kB 10 ms
index.html Finished text/html Other 972 B 1 ms
似乎 HTML 节点已被删除,浏览器正在预取代码。这很可能发生,因为 HTML 文档本身无论如何都会传输。然后浏览器解析 HTML 并查看所有要请求的文件。一旦 HTML 文档转换为 DOM,浏览器就会运行观察者,删除节点,并且不会及时从观察者之后的节点执行 JavaScript 。
请参阅这个反例,我在其中注释掉观察部分:
// observer.observe(document.head, { childList: true });
在这种情况下,控制台输出将显示:
test.js:1 I got loaded before you could remove me.
网络面板看起来没有什么不同。因此,当我使用 Chrome 时,它会尝试以完美的速度加载和缓存 JavaScript,但由于它的节点被删除,它不会执行它。
可能的 TagManager / Google Anyltics 见解
如果您有权更改 TagManager 的标签,您可能只需添加<script>console.log("TagManager code executed");</script>
并确认这样就可以正确地抑制已删除标签的代码执行。因此,使用本地 JS 文件但直接在 TagManager 中确认与我的示例相同。
另一种方式是 Google TagManager 的优秀 Debug 模式。
如果此处也使用了 Google Analytics,您可能会在GA Real-Time 视图中看到您的请求(或缺少请求) (嗯......没有屏幕截图的糟糕文档。只需在 Analytics 中查找实时,您就会找到它)。
推荐阅读
- java - JPA查询多列,如果空列数据忽略查询和数据中的列
- java - 尝试打开从 java 到 hive 的 jdbc 连接时,GSS 启动失败
- c# - 有人可以解释一下这个 c# 语法吗?
- python - 如何解决 /wd/hub/session java.io.IOException:在 docker 的 selenium 网格上运行机器人框架测试用例时?
- r - 在 for 循环中使用 dplyr::filter 创建新数据框
- angular - Angular 6 - 从另一个组件调用模态窗口组件
- chromium - 我可以使用 ffmpeg 构建 chromium 以支持所有视频格式吗?
- c++ - 在另一个 Widget 中更改 QWidget 的背景颜色
- swift - 类属性返回 nil
- dynamics-crm - Microsoft Dynamics CRMv4 中的唯一字段