堆栈在第0行溢出

我有一个表单validation脚本,不幸的是在崩溃之前不久(IE7) Stack overflow at line 0警报框中返回Stack overflow at line 0并且在IE8中直接崩溃(它确实首先工作,非常慢)。

我已经为你的测试乐趣制作了一个jsFiddle: http : //jsfiddle.net/yuNXm/2/在你输入一个需要validation然后失去焦点的输入值之后发生堆栈溢出。 (电子邮件字段是ajax驱动的,因此不会在那里运行)。

相关的Javascript:

 jQuery(document).ready(function($) { var inputs = $('input[data-validation-method]'); var fields = $(); var classes = ['fail', 'win']; //Methods of validation, must return an object like so {result: [boolean], message: [string or false]} as a parameter of the callback() function; var methods = { 'email' : function(field, dependancies, callback) { var value = field.val(); var response = false; field.addClass("loading"); $.post( ajaxData.url, { 'action':'validate_form', 'value': value, 'method': field.data('method') }, function(response){ return callback(response); } ).complete(function() { field.removeClass("loading"); }); }, 'password' : function(field, dependancies, callback) { var value = field.val(); var response = {}; if (value.length < 8) { response.result = false; response.message = 'Your password must be a minimum of 8 characters'; } else { response.result = true; response.message = false; } return callback(response); }, 'verify_password' : function(field, dependancies, callback) { var value = field.val(); var response = {}; if (value != dependancies["password"].val()) { if (!dependancies["password"].val() || !value) { return false; } response.result = false; response.message = 'Passwords do no match'; } else { response.result = true; response.message = false; } return callback(response); } } // Prepare fields for validation inputs.each(function() { createField($(this)); }); function createField (field) { inputs = inputs.not(field); var method = field.attr('data-validation-method'); var requires = field.attr('data-validation-requires'); if (!!requires) { requires = requires.split(','); var dependancies = {}; $.each(requires, function(key, value) { var element = $('#' + value); if(element.length) { dependancies[element.attr('id')] = element; if(inputs.find(element).length) { createField(element); } if ($.isArray(element.data('linked_fields'))) { element.data('linked_fields').push(field); } else { element.data('linked_fields', [field]); } } }); } if (methods[method]) { fields = fields.add('#' + field.attr('id')); field.data('method', method); field.data('dependancies', dependancies); } } function validate (field) { var callback = function(response) { field.data('response', response); if (response) { toggleFlag(field, 'show'); } else { toggleFlag(field, 'remove'); } if($.isArray(field.data('linked_fields'))) { $.each(field.data('linked_fields'), function(key, value) { validate(value); }); } } methods[field.data('method')](field, field.data('dependancies'), callback); } fields.focus(function() { var field = $(this); field.data("value", field.val()); field.bind("propertychange keyup input paste", function(event){ if(field.data("response") && (field.val() != field.data("value"))) { toggleFlag(field, "hide"); if($.isArray(field.data('linked_fields'))) { $.each(field.data('linked_fields'), function(key, value) { toggleFlag(value, "hide"); }); } } }); }); fields.blur(function() { var field = $(this); if (field.val().length) { if (field.val() != field.data("value")) { toggleFlag(field, "remove"); validate(field); } else { toggleFlag(field, "show"); } } else { toggleFlag(field, "remove"); } }); function toggleFlag (field, method) { var flag = field.data("flag"); var response = field.data("response"); if (response) { switch (method) { case "show": if (response.message) { if(!flag) { flag = $('' + response.message + '').insertAfter(field); field.data("flag", flag); flag.hide(); } if (!flag.data("active")) { flag.data("active", true); flag.stop(true, true).animate({height: "show", opacity: "show"}, 500); } } field.addClass(classes[~~response.result]); break; case "hide": if (flag) { if (flag.data("active")) { flag.data("active", false); flag.stop(true, true).animate({height: "hide", opacity: "hide"}, 500); } } field.removeClass(classes[~~response.result]); break; case "remove": if (flag) { field.removeData("flag"); if (flag.data("active")) { flag.stop(true, true).animate({height: "hide", opacity: "hide"}, 100, function() { flag.remove(); }); } } field.removeClass(classes[~~response.result]); field.removeData("response"); break; } } } }); 

相关的HTML:

 
We won\'t do anything cheeky with your email... promise. We won\'t spam your inbox, emails will be infrequent.

现在我知道这通常是由于递归,我在脚本的两个区域使用递归。

重复function1:

 function createField (field) { inputs = inputs.not(field); var method = field.attr('data-validation-method'); var requires = field.attr('data-validation-requires'); if (!!requires) { requires = requires.split(','); var dependancies = {}; $.each(requires, function(key, value) { var element = $('#' + value); if(element.length) { dependancies[element.attr('id')] = element; if(inputs.find(element).length) { createField(element); } if ($.isArray(element.data('linked_fields'))) { element.data('linked_fields').push(field); } else { element.data('linked_fields', [field]); } } }); } if (methods[method]) { fields = fields.add('#' + field.attr('id')); field.data('method', method); field.data('dependancies', dependancies); } } 

因为只有当您与需要validation的输入交互时才会发生堆栈溢出,并且createField函数仅用作初始化函数,我认为不是这个。

重复function2:

 function validate (field) { var callback = function(response) { field.data('response', response); if (response) { toggleFlag(field, 'show'); } else { toggleFlag(field, 'remove'); } if($.isArray(field.data('linked_fields'))) { $.each(field.data('linked_fields'), function(key, value) { validate(value); }); } } methods[field.data('method')](field, field.data('dependancies'), callback); } 

我无法访问任何其他外部程序来调试此(企业环境),任何人都可以引导我朝着正确的方向前进吗?

每当您使用jQuery addClassremoveClass时,Internet Explorer都会触发事件propertychange更改。 问题代码在这里:

  var field = $(this); field.data("value", field.val()); field.bind("propertychange keyup input paste", function(event){ if(field.data("response") && (field.val() != field.data("value"))) { toggleFlag(field, "hide"); if($.isArray(field.data('linked_fields'))) { $.each(field.data('linked_fields'), function(key, value) { toggleFlag(value, "hide"); }); } } }); 

在你的toggleFlag函数中,你可以调用jQuery的addClassremoveClass 。 这创建了导致堆栈溢出的无限递归循环。

如果您取出了propertychange它在Internet Explorer以及所有其他浏览器上运行良好。

工作示例: http //jsfiddle.net/yuNXm/9/

您在Internet Explorer上遇到此问题的原因是onpropertychange是Microsoft为Internet Explorer实现的专有事件。 它没有被其他浏览器实现。

使用IE6-8调试堆栈溢出:

您将来可以用来诊断这些类型的堆栈溢出的好方法是:

  1. 确定无限递归循环所涉及的函数之一。 如果您在没有调试function的情况下坚持使用IE6-8,那么这需要在各种function中放置警报,直到您找到无限循环function。

  2. 将这行代码放在函数的顶部:

    alert(arguments.callee.caller.toString());

此警报将告诉您哪个函数正在调用无限循环函数。 然后通过回溯无限递归循环中涉及哪些函数,您可以隔离代码中需要仔细检查无限循环原因的部分。

当然,如果你有一个带有适当调试工具的现代网络浏览器,这不是必需的 – 你只需要逐步完成代码。

另一方面,我感受到了你的痛苦。 我的部分工作还涉及为企业客户编写JavaScript,其中IE6-8通常是他们的IT部门强加的浏览器。没有调试工具,只有警报和评论; 在对堆栈溢出进行故障排除时,甚至不能使用行号。