尝试捕获许多脚本组件的错误 - JavaScript

Try Catch Errors many script components - JavaScript

我有一个包含许多脚本组件 (50+) 的页面,并且在随机使用 IE 时出现错误(在 Chrome 或 Firefox 中不会发生)。

"Out of Memory at line: 1"

我也进行了一些 google 搜索,这揭示了 IE 处理问题的方式与 Chrome 和 FF 不同。我想捕获此错误并确切知道该脚本错误的原因是什么。

在这么多脚本组件上使用全局 try-catch 块的最佳方法是什么?所有这些脚本组件都在同一页面上。期待您的建议。

您可能想尝试 window.onerror 作为起点。它需要添加在加载组件的 <script> 标签之前。

https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onerror

如果失败,您可以尝试将加载的组件减少一半,直到错误不再发生。然后,对页面进行概要分析(由于概要分析的需要,您可能需要进一步减少)。按照@Bergi 的建议查找内存泄漏。如果确实存在泄漏,它可能会在所有浏览器中发生,因此您也可以在 Chrome 中进行故障排除。

如果仍然未能产生任何有趣的结果,则问题可能出在某个特定组件中,而该组件不在您正在加载的组件集中。理想情况下,只要包含该组件,您就会看到问题。您可以反复平分加载的组件,直到找出罪魁祸首。

最后,忘了说,你做这一切的基础应该是浏览器的开发者工具,例如Chrome dev tools, or if it is unique to Edge, Edge debugger.

仅供参考,Edge 是崩溃的浏览器,但这并不意味着 Chrome 或 FF 中不存在此问题。

您的问题中缺少的一件重要事情是错误是在 页面加载或初始化 期间发生,还是在 一段时间后 [=59] 发生=] 当您浏览页面时。

如果是在加载或者初始化的时候,很可能是因为你的页面包含了太多的组件,占用的内存也远远超过了浏览器愿意接受的程度(而IE是第一个放弃的)。

在这种情况下,只能减小页面大小。一种可能的方法是只创建当前可见的对象(组件)(在视口中),一旦它们离开视口就将它们从 JS 中删除并再次 DOM (用大小与组件大小相符的空 DIV 替换)。


如果在浏览页面时出现错误,可能是内存泄漏引起的。您可以使用 Process Explorer 查看浏览器使用的内存并检查内存是否不断增加 - 这表明内存泄漏。

Internet Explorer 中可能会发生内存泄漏,因为它包含 2 个独立的垃圾收集器(又名 GC):一个用于 DOM 对象,另一个用于 JS 属性。其他浏览器(FF、Webkit、Chromium 等;不确定 Edge)只包含一个 GC 用于 DOM 和 JS。

所以当你在DOM对象和JS对象之间创建循环引用时,IE的GC不能正确释放内存而造成内存泄漏。

var myGlobalObject;

function SetupLeak()
{
  myGlobalObject = document.getElementById("LeakDiv");
  document.getElementById("LeakDiv").expandoProperty = myGlobalObject;

  //When reference is not required anymore, make sure to release it
  myGlobalObject = null;
}

在这段代码之后,LeakDiv 引用似乎被释放了,但 LeakDiv 仍然在其 expandoProperty 中引用 myGlobalObject,后者又引用了 LeakDiv .在其他浏览器中,他们的 GC 可以识别这种情况并释放 myGlobalObjectLeakDiv 但 IE 的 GC 不能,因为他们不知道引用的对象是否仍在使用(因为这是其他 GC 的责任).

更不明显的是由闭包创建的循环引用:

function SetupLeak()
{
    // The leak happens all at once
    AttachEvents( document.getElementById("LeakedDiv"));
}

function AttachEvents(element)
{
    //attach event to the element
    element.attachEvent("onclick", function {
            element.style.display = 'none';
    });
}

在这种情况下,LeakedDivonclick 属性 引用处理程序 function,其闭包 element 属性 引用 LeakedDiv.

要解决这些情况,您需要正确删除 DOM 对象和 JS 变量之间的所有引用:

function FreeLeak()
{
    myGlobalObject = null;
    document.getElementById("LeakDiv").expandoProperty = null;
}

并且您可能希望减少(或完全删除)在 DOM 个元素上创建的闭包:

function SetupLeak()
{
    // There is no leak anymore
    AttachEvents( "LeakedDiv" );
}

function AttachEvents(element)
{
    //attach event to the element
    document.getElementById(element).attachEvent("onclick", function {
            document.getElementById(element).style.display = 'none';
    });
}

在这两种情况下,都不能使用 try-catch,因为内存不足可能发生在代码中的随机位置,即使您找到下一次发生内存不足的代码行,它也可能发生在其他地方。 Process Explorer 是找到内存增加的情况并尝试猜测可能导致它的原因的最佳机会。

例如:如果每次打开和关闭菜单(如果有的话)内存都会增加,那么您应该查看它是如何打开和关闭的,并寻找上述情况。

您可以在调用任何组件之前和之后检查您的 localStorage

类似于:

function getLocalStorage() {
    return JSON.stringify(localStorage).length;
}

function addScript(src, log) {
    if(log){
        console.log("Adding " + src + ", local storage size: " + getLocalStorage());
    }
    var s = document.createElement( 'script' );
    s.setAttribute( 'src', src );
    document.body.appendChild( s );
}

function callFunction(func, log){
    if(log){
        console.log("Calling " + func.name + ", local storage size: " + getLocalStorage());
    }
    func();
}

try {
    addScript(src1, true);
    addScript(src2, true);
    callFunction(func1, true);
    callFunction(func2, true);
}
catch(err) {
    console.log(err.message);
}

希望对你有所帮助。再见