WordPress AJAX表单报错Uncaught RangeError及实现问题求助
错误现象
提交表单时触发Uncaught RangeError: Maximum call stack size exceeded栈溢出错误,随后页面自动刷新。
核心错误原因及代码问题点
PHP代码问题
无限递归导致栈溢出
在snek_roll函数内部的roll_dice方法中,当返回值为0时,直接递归调用roll_dice()但未处理返回结果,也没有终止条件。如果连续多次随机出0,会触发无限递归,耗尽调用栈内存,抛出栈溢出错误。AJAX动作名称不匹配
PHP中注册的AJAX动作是wp_ajax_snek_roll,对应请求的action参数应该是snek_roll,但JS代码中传入的是action: "snek_results",导致后台无法找到对应的处理函数,请求失效。脚本本地化调用时机错误
wp_localize_script在init钩子外部调用,此时snek_results脚本还未完成注册,会导致本地化失败,无法正确传递ajaxurl。函数嵌套定义不合理
roll_dice函数定义在snek_roll内部,每次调用snek_roll都会重新定义该函数,虽然不会直接引发错误,但不符合代码规范,影响性能和可维护性。
JavaScript代码问题
未定义变量导致请求参数错误
AJAX请求的data字段中使用了bet和choice变量,但这两个变量并未定义,应该使用之前声明的formData.bet和formData.choice,否则请求参数为空,触发PHP的错误检查逻辑。阻止默认提交时机错误
event.preventDefault()放在AJAX调用之后,由于AJAX是异步执行,可能在preventDefault生效前,表单已经完成默认提交,导致页面刷新。重复的DOM就绪监听
jQuery(function($) {})已经等价于$(document).ready(),内部再嵌套$(document).ready()属于冗余代码,无意义。
修复后的代码示例
修复后的PHP代码
function my_script_enqueuer() { wp_register_script( "snek_results", get_template_directory_uri() . '-child/js/results.js', array('jquery') ); wp_localize_script( 'snek_results', 'snek_results', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ))); wp_enqueue_script( 'snek_results'); } add_action( 'wp_enqueue_scripts', 'my_script_enqueuer' ); add_action("wp_ajax_snek_roll", "snek_roll"); add_action("wp_ajax_nopriv_snek_roll", "snek_roll"); // 允许未登录用户访问 function roll_dice() { $roll_min = 1000; $roll_max = 100000; $roll = random_int($roll_min, $roll_max); $result = $roll % 4; // 循环直到得到非0结果,避免递归 while ($result === 0) { $roll = random_int($roll_min, $roll_max); $result = $roll % 4; } return $result; } function snek_roll() { $choice = isset($_REQUEST['choice']) ? intval($_REQUEST['choice']) : ''; $bet = isset($_REQUEST['bet']) ? intval($_REQUEST['bet']) : ''; ### ERROR CHECKING ### if (empty($choice)) { $status = array( "status" => "error", "results" => "no selection made.", ); echo json_encode($status); wp_die(); // WordPress推荐用wp_die替代exit } if (empty($bet)) { $status = array( "status" => "error", "results" => "no bet made.", ); echo json_encode($status); wp_die(); } ### ACTION ### $results = roll_dice(); if ($choice == $results) { $status = array( "status" => "winner", "choice" => $choice, "results" => $results, "bet" => $bet, "prize" => $bet * 2.5 ); } else { $status = array( "status" => "loser", "choice" => $choice, "results" => $results, "bet" => $bet, "prize" => 0 ); } echo json_encode($status); wp_die(); }
修复后的JavaScript代码
jQuery(function($) { $("form").submit(function (event) { // 先阻止默认提交行为 event.preventDefault(); var formData = { action: "snek_roll", // 匹配PHP的AJAX动作名称 choice: $("input[name='choice']:checked").val(), bet: $("input[name='bet']:checked").val() }; $.ajax({ type: "POST", url: snek_results.ajaxurl, data: formData, dataType: "json", encode: true, }).done(function (data) { if (data.status) { $('#results').html("Status: " + data.status); } }).fail(function(xhr, status, error) { // 增加错误处理 $('#results').html("请求出错: " + error); }); }); });
内容的提问来源于stack exchange,提问作者jon

