如何在Safari中找到页面持续刷新的原因?

4
我正在解决一个客户网站的问题,这个问题出现在过去一个月左右,可能是由于iOS和OSX的最新更新。当使用Mac或iOS Safari通过EDM中的链接跳转到该网站的任何页面时,他们会被困在不断刷新的循环中。似乎在刷新之间还会泄漏内存,因为Activity Monitor显示网站的Safari Web Content进程在内存使用方面快速增长(在两分钟左右达到4GB之后我就杀死了它)。
这个问题只能在Safari浏览器上重现。Mac上的Chrome似乎没有受到影响。Windows的Safari显示刷新问题,但似乎并没有开始hoarding memory,尽管WebKit2WebProcess.ee进程的CPU使用率一直维持在相当高的水平,直到窗口关闭。我尝试逐个删除EDM链接中添加的utm_*参数,直到确认问题仅由utm_source本身引起,然后发现我应该意识到这是GA寻找的主要标签。更有趣的是,删除GA并没有解决这个问题,我注释掉了创建脚本标签的代码(值得一提的是,使用的脚本不是通常的www.google-analytics.com/ga.js,而是stats.g.doubleclick.net/dc.js中的DFP脚本)。
解决此问题的方法是不加载GPT - 注释掉以下代码:
var googletag = googletag || {};
    googletag.cmd = googletag.cmd || [];
    (function() {
        var gads = document.createElement("script");
        gads.async = true;
        gads.type = "text/javascript";
        var useSSL = "https:" == document.location.protocol;
        gads.src = (useSSL ? "https:" : "http:") + "//www.googletagservices.com/tag/js/gpt.js";
        var node =document.getElementsByTagName("script")[0];
        node.parentNode.insertBefore(gads, node);
    })();

我相信GPT正在检测utm_source参数并尝试执行某些操作,但在Safari上由于某些原因失败。不幸的是,GPT代码被混淆了,我很难通过阅读代码找到问题。因此,我希望能够在Safari开发者控制台中,在页面刷新之前获取调用堆栈,或者使用其他调试技术。也许有人遇到过这个问题?
据我所知,唯一关心这些参数的脚本是Google Analytics,所以我也愿意听取别人的意见。
编辑:我尝试取消注释GPT脚本标记,然后注释页面上我们向其中推送命令(使用googletag.cmd.push())的地方,以防我们使用它引起问题(我们基本上只定义然后发布8个插槽,然后启用广告服务)。但是注释此命令未解决问题,似乎与已加载GPT有关。
1个回答

3

这个问题非常令人困惑,即使在我修复后仍然如此。

我们通过更新正在使用的History.js库解决了该问题,就此而言,我完全可以接受它作为有效的故障排除步骤(因此我试用了它)。然而,我完全不明白History.js和gpt.js如何相互交互,并导致问题仅发生在以下情况下:

使用Safari 使用较旧版本的History.js 使用GPT(对History.js应该没有影响) 使用utm_source标记(对History.js或GPT都不应产生影响)

但是,我更愿意困惑于已修复的问题而不是普遍存在的问题,所以我将把它放在“太难”的篮子里。

顺便提一下,我的主要问题与问题本身无关,而是如何进行故障排除,以达到结论,以防对其他人有帮助:

  • I added a script tag at the top of <head> which registered an event handler for beforeunload, calling the debugger statement. This would give me time to actually inspect the timeline and profiler before the page refreshed.
  • This showed me that immediately before the beforeunload event, a popstate event was called (with the benefit of hindsight I berate myself for not going straight to History.js when I saw popstate). This event installed a timer, which I noted was fired immediately, then every 1000 ms. It was the last thing to fire in the popstate event before the beforeunload event, so I figured there was a good chance it was causing the refresh.
  • Next, I spent some time pulling my hair out at the fact that safari does not expose the call stack of events in it's timeline. I know how to get that in Chrome, but I can't make the issue happen in Chrome. All I had to go on was the timer ID. Eventually I overrode the setTimeout like so:

    var origST = window.setTimeout;
    window.timers = [];
    window.setTimeout = function(f,t) {
      window.timers[origST(f,t)] = window.setTimeout.caller ? window.setTimeout.caller : 'Global Scope';
    }
    
  • And did the same for setInterval. Then I could reload the page, get the ID of the timer and then in the console check timers[the id] for the text of the function which had installed the timer.

  • Next I needed to search all the loaded script files for the function definition in question (it was an obfuscated and uglified script, not something I could easily guess) I'm not sure if this is actually possible in Safari, if it is I couldn't figure out how. Luckily this doesn't rely on reproducing the issue so I loaded up Chrome and used it's dev tools to search the script files.
  • Finding the function in History.js, we updated it and found the issue resolved.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接