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

时间:2022-10-28 14:42:36

I have a page that contains many script components (50+) and I am getting an error when using IE at some random instance (doesn't happen in Chrome or Firefox).

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

"Out of Memory at line: 1"

“内存不足1行”

I've done some google search too and that reveals issues with IE handling things differently to Chrome and FF. I would like to catch this error and know exactly what the cause of that script error is.

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

What would be the best way to use a global try-catch block on that many script components? All these script components are on the same page. Looking forward to your suggestions.

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

3 个解决方案

#1


3  

You might want to try window.onerror as a starting point. It will need to be added before the <script> tags that load the components.

您可能希望尝试使用window.onerror作为起点。它需要在加载组件的

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

If that fails, you might try reducing the components loaded by half until the error no longer occurs. Then, profile the page (you may have to reduce further due to the demand of profiling). Look for a memory leak as @Bergi suggested. If there is in fact a leak, it will likely occur in all browsers, so you can trouble-shoot in Chrome, as well.

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

If that still fails to yield anything interesting, the issue may be in one particular component that was not in the set of components you were loading. Ideally, anytime that component is included you see the issue. You could repeatedly bisect the loaded components until you isolate the culprit.

如果仍然没有产生任何有趣的东西,那么问题可能出在一个特定的组件中,该组件不在您加载的组件集中。理想情况下,只要包含该组件,您就会看到问题。您可以重复平分加载的组件,直到您找出罪魁祸首。

Finally, forgot to mention, your home-base for all of this should be the browser's developer tools, e.g. Chrome dev tools, or if it is unique to Edge, Edge debugger.

最后,忘了提一下,你所有这一切的家庭基础应该是浏览器的开发者工具,例如: Chrome开发工具,或者它是Edge,Edge调试器所独有的。

And FYI, Edge is the browser that crashes, but that does not mean the issue is not present in Chrome or FF.

而且,FYI,Edge是崩溃的浏览器,但这并不意味着Chrome或FF中不存在该问题。

#2


2  

One important thing that is missing in your question is if the error happens during the page loading or initialization or if it happens after some time while you browse the page.

您的问题中缺少的一件重要事情是,如果在页面加载或初始化期间发生错误,或者在浏览页面的某段时间后发生错误。

If it's during loading or initialization, it's probably caused by the fact that your page contains too many components and uses much more memory than the browser is willing to accept (and IE is simply the first one to give up).

如果它是在加载或初始化期间,它可能是由于您的页面包含太多组件并使用比浏览器愿意接受的内存多得多的事实(并且IE只是第一个放弃的)。

In such case there is no helping but reduce the page size. One possible way is to create only objects (components) that are currently visible (in viewport) and as soon as they get out of the viewport remove them from JS and DOM again (replacing the with empty DIVs sized to the size of the components).

在这种情况下,没有帮助,但减少页面大小。一种可能的方法是只创建当前可见的对象(组件)(在视口中),一旦它们离开视口,再次从JS和DOM中删除它们(用大小为组件大小的空DIV替换) 。


In case the error happens while browsing the page, it may be caused by a memory leak. You may use Process Explorer to watch the memory used by your browser and check if the memory constantly increase - which would indicate the memory leak.

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

Memory leak in Internet Explorer may happen because it contains 2 separate garbage collectors (aka GC): one for DOM objects and other for JS properties. Other browsers (FF, Webkit, Chromium, etc.; not sure about the Edge) contains only one GC for both DOM and JS.

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

So when you create circular reference between DOM object and JS object, IE's GC cannot correctly release the memory and creates a memory leak.

因此,当您在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;
}

After this code it seems the LeakDiv reference was freed but LeakDiv still reference the myGlobalObject in its expandoProperty which in turn reference the LeakDiv. In other browsers their GC can recognize such situation and release both myGlobalObject and LeakDiv but IE's GCs cannot because they don't know if the referenced object is still in use or not (because it's the other GC's responsibility).

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

Even less visible is a circular reference created by a closure:

更不可见的是闭包创建的循环引用:

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';
    });
}

In this case the LeakedDiv's onclick property references the handler function whose closure element property reference the LeakedDiv.

在这种情况下,LeakedDiv的onclick属性引用其封闭元素属性引用LeakedDiv的处理函数。

To fix these situations you need to properly remove all references between DOM objects and JS variables:

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

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

And you may want to reduce (or remove completely) closures created on DOM elements:

并且您可能希望减少(或完全删除)在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';
    });
}

In both cases using try-catch is not the option because the Out of memory may happen on random places in code and even if you find one line of code where it's happened the next time it may be elsewhere. The Process Explorer is the best chance to find the situations when the memory increase and and trying to guess what may be causing it.

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

For example: if the memory increase every time you open and close the menu (if you have one) then you should look how it's being opened and closed and look for the situations described above.

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

#3


1  

You could check your localStorage before and after any components called.

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

Something like:

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);
}

I hope it helps you. Bye.

我希望它对你有所帮助。再见。

#1


3  

You might want to try window.onerror as a starting point. It will need to be added before the <script> tags that load the components.

您可能希望尝试使用window.onerror作为起点。它需要在加载组件的

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

If that fails, you might try reducing the components loaded by half until the error no longer occurs. Then, profile the page (you may have to reduce further due to the demand of profiling). Look for a memory leak as @Bergi suggested. If there is in fact a leak, it will likely occur in all browsers, so you can trouble-shoot in Chrome, as well.

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

If that still fails to yield anything interesting, the issue may be in one particular component that was not in the set of components you were loading. Ideally, anytime that component is included you see the issue. You could repeatedly bisect the loaded components until you isolate the culprit.

如果仍然没有产生任何有趣的东西,那么问题可能出在一个特定的组件中,该组件不在您加载的组件集中。理想情况下,只要包含该组件,您就会看到问题。您可以重复平分加载的组件,直到您找出罪魁祸首。

Finally, forgot to mention, your home-base for all of this should be the browser's developer tools, e.g. Chrome dev tools, or if it is unique to Edge, Edge debugger.

最后,忘了提一下,你所有这一切的家庭基础应该是浏览器的开发者工具,例如: Chrome开发工具,或者它是Edge,Edge调试器所独有的。

And FYI, Edge is the browser that crashes, but that does not mean the issue is not present in Chrome or FF.

而且,FYI,Edge是崩溃的浏览器,但这并不意味着Chrome或FF中不存在该问题。

#2


2  

One important thing that is missing in your question is if the error happens during the page loading or initialization or if it happens after some time while you browse the page.

您的问题中缺少的一件重要事情是,如果在页面加载或初始化期间发生错误,或者在浏览页面的某段时间后发生错误。

If it's during loading or initialization, it's probably caused by the fact that your page contains too many components and uses much more memory than the browser is willing to accept (and IE is simply the first one to give up).

如果它是在加载或初始化期间,它可能是由于您的页面包含太多组件并使用比浏览器愿意接受的内存多得多的事实(并且IE只是第一个放弃的)。

In such case there is no helping but reduce the page size. One possible way is to create only objects (components) that are currently visible (in viewport) and as soon as they get out of the viewport remove them from JS and DOM again (replacing the with empty DIVs sized to the size of the components).

在这种情况下,没有帮助,但减少页面大小。一种可能的方法是只创建当前可见的对象(组件)(在视口中),一旦它们离开视口,再次从JS和DOM中删除它们(用大小为组件大小的空DIV替换) 。


In case the error happens while browsing the page, it may be caused by a memory leak. You may use Process Explorer to watch the memory used by your browser and check if the memory constantly increase - which would indicate the memory leak.

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

Memory leak in Internet Explorer may happen because it contains 2 separate garbage collectors (aka GC): one for DOM objects and other for JS properties. Other browsers (FF, Webkit, Chromium, etc.; not sure about the Edge) contains only one GC for both DOM and JS.

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

So when you create circular reference between DOM object and JS object, IE's GC cannot correctly release the memory and creates a memory leak.

因此,当您在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;
}

After this code it seems the LeakDiv reference was freed but LeakDiv still reference the myGlobalObject in its expandoProperty which in turn reference the LeakDiv. In other browsers their GC can recognize such situation and release both myGlobalObject and LeakDiv but IE's GCs cannot because they don't know if the referenced object is still in use or not (because it's the other GC's responsibility).

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

Even less visible is a circular reference created by a closure:

更不可见的是闭包创建的循环引用:

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';
    });
}

In this case the LeakedDiv's onclick property references the handler function whose closure element property reference the LeakedDiv.

在这种情况下,LeakedDiv的onclick属性引用其封闭元素属性引用LeakedDiv的处理函数。

To fix these situations you need to properly remove all references between DOM objects and JS variables:

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

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

And you may want to reduce (or remove completely) closures created on DOM elements:

并且您可能希望减少(或完全删除)在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';
    });
}

In both cases using try-catch is not the option because the Out of memory may happen on random places in code and even if you find one line of code where it's happened the next time it may be elsewhere. The Process Explorer is the best chance to find the situations when the memory increase and and trying to guess what may be causing it.

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

For example: if the memory increase every time you open and close the menu (if you have one) then you should look how it's being opened and closed and look for the situations described above.

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

#3


1  

You could check your localStorage before and after any components called.

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

Something like:

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);
}

I hope it helps you. Bye.

我希望它对你有所帮助。再见。