首页 > 解决方案 > 如何在加载之前可靠地删除脚本标签?

问题描述

我创建了一个突变观察者来在某些条件下删除(阻止)脚本。

有几种 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>
    ```

标签: javascriptjquery

解决方案


应该改为添加脚本

正如评论中所讨论的,用观察者删除脚本是不可靠的。

  • 浏览器可以在知道 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=​&quot;test.js">​&lt;/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 中查找实时,您就会找到它)。


推荐阅读