尝试捕获许多脚本组件的错误 - 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 可以识别这种情况并释放 myGlobalObject
和 LeakDiv
但 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';
});
}
在这种情况下,LeakedDiv
的 onclick
属性 引用处理程序 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);
}
希望对你有所帮助。再见
我有一个包含许多脚本组件 (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 可以识别这种情况并释放 myGlobalObject
和 LeakDiv
但 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';
});
}
在这种情况下,LeakedDiv
的 onclick
属性 引用处理程序 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);
}
希望对你有所帮助。再见