为何原生alert()会在自定义alertbox()函数之前执行?
问题描述
我自定义了alertbox()函数,按顺序先调用alertbox('Confirm to Cancel?', 'Confirmation'),再调用原生alert(alertbox_clicked_button_id),但实际运行时原生alert()反而先弹出,和预期的执行顺序相反。
原代码
alertbox('Confirm to Cancel?', 'Confirmation'); alert(alertbox_clicked_button_id); var alertbox_clicked_button_id = ''; function alertbox(alert_text, alert_header = 'INFORMATION', alert_truebutton = 'Yes', alert_falsebutton = 'No') { $('#alert-header').text(''); $('#alert-body').text(''); $('#alert-truebutton').hide(); $('#alert-falsebutton').hide(); var xalert_text = alert_text; var xalert_header = alert_header.toUpperCase(); var xalert_color = ''; var waitingtime = 5000; if (xalert_header == 'ERROR' || xalert_header == 'E') { xalert_header = 'ERROR'; xalert_color = 'red'; waitingtime = 0; } else if (xalert_header == 'SUCCESS' || xalert_header == 'S') { xalert_header = 'SUCCESS'; xalert_color = 'green'; } else if (xalert_header == 'INFORMATION' || xalert_header == 'I') { xalert_header = 'INFORMATION'; xalert_color = 'teal'; } else if (xalert_header == 'MESSAGE' || xalert_header == 'M') { xalert_header = 'MESSAGE'; xalert_color = 'blue'; } else if (xalert_header == 'WARNING' || xalert_header == 'W') { xalert_header = 'WARNING'; xalert_color = 'purple'; } else if (xalert_header == 'CONFIRMATION' || xalert_header == 'C') { waitingtime = 0; xalert_header = 'CONFIRMATION'; xalert_color = 'green'; $('#alert-truebutton').show(); $('#alert-falsebutton').show(); $('#alert-truebutton').html(alert_truebutton); $('#alert-falsebutton').html(alert_falsebutton); } $('#alert-body').html(xalert_text); $('#alert-header').text(xalert_header); $('#alert-header-div').css('background-color', xalert_color); $('#alert-closebutton').css('background-color', xalert_color); //$('#alertmodal').modal('show'); if (waitingtime > 0) { AutoCloseDialogBox(waitingtime); } } function AutoCloseDialogBox(WaitSeconds) { setTimeout(function() { $('#alertmodal').modal('hide'); alertbox_clicked_button_id = 'alert-closebutton'; }, WaitSeconds); } function alertfunction(pass_id) { $('#alertmodal').modal('hide'); alertbox_clicked_button_id = pass_id; }
问题原因
- 同步执行阻塞:原生
alert()是同步阻塞式弹窗,会立即暂停JavaScript线程执行。而alertbox里的DOM更新(包括模态框显示)属于浏览器渲染任务,需要等当前同步代码执行完才会处理。所以调用alertbox后,还没等模态框渲染出来,alert()就先弹出来了。 - 异步逻辑滞后:
alertbox_clicked_button_id的赋值逻辑(按钮点击、自动关闭)都是异步触发的(依赖setTimeout或DOM事件),但在同步代码里直接调用alert()时,变量还没被赋值,拿到的只是初始空字符串。 - 变量声明顺序问题:
alertbox_clicked_button_id在调用之后才声明,虽然变量提升会让它存在,但初始状态是undefined,不符合预期逻辑。
解决方案
通过添加回调函数,把原生alert()的执行逻辑放到alertbox交互完成后的异步回调里,确保顺序正确:
修改后的代码
// 提前声明变量,避免变量提升问题 var alertbox_clicked_button_id = ''; // 给alertbox添加回调参数,接收交互完成后的执行逻辑 function alertbox(alert_text, alert_header = 'INFORMATION', alert_truebutton = 'Yes', alert_falsebutton = 'No', callback) { $('#alert-header').text(''); $('#alert-body').text(''); $('#alert-truebutton').hide(); $('#alert-falsebutton').hide(); var xalert_text = alert_text; var xalert_header = alert_header.toUpperCase(); var xalert_color = ''; var waitingtime = 5000; if (xalert_header == 'ERROR' || xalert_header == 'E') { xalert_header = 'ERROR'; xalert_color = 'red'; waitingtime = 0; } else if (xalert_header == 'SUCCESS' || xalert_header == 'S') { xalert_header = 'SUCCESS'; xalert_color = 'green'; } else if (xalert_header == 'INFORMATION' || xalert_header == 'I') { xalert_header = 'INFORMATION'; xalert_color = 'teal'; } else if (xalert_header == 'MESSAGE' || xalert_header == 'M') { xalert_header = 'MESSAGE'; xalert_color = 'blue'; } else if (xalert_header == 'WARNING' || xalert_header == 'W') { xalert_header = 'WARNING'; xalert_color = 'purple'; } else if (xalert_header == 'CONFIRMATION' || xalert_header == 'C') { waitingtime = 0; xalert_header = 'CONFIRMATION'; xalert_color = 'green'; $('#alert-truebutton').show(); $('#alert-falsebutton').show(); $('#alert-truebutton').html(alert_truebutton); $('#alert-falsebutton').html(alert_falsebutton); } $('#alert-body').html(xalert_text); $('#alert-header').text(xalert_header); $('#alert-header-div').css('background-color', xalert_color); $('#alert-closebutton').css('background-color', xalert_color); $('#alertmodal').modal('show'); // 取消注释,正常显示模态框 if (waitingtime > 0) { AutoCloseDialogBox(waitingtime, callback); } // 绑定按钮点击事件,触发回调 $('#alert-truebutton').off('click').on('click', function() { alertfunction('alert-truebutton', callback); }); $('#alert-falsebutton').off('click').on('click', function() { alertfunction('alert-falsebutton', callback); }); $('#alert-closebutton').off('click').on('click', function() { alertfunction('alert-closebutton', callback); }); } function AutoCloseDialogBox(WaitSeconds, callback) { setTimeout(function() { $('#alertmodal').modal('hide'); alertbox_clicked_button_id = 'alert-closebutton'; // 执行回调函数 if (typeof callback === 'function') { callback(alertbox_clicked_button_id); } }, WaitSeconds); } function alertfunction(pass_id, callback) { $('#alertmodal').modal('hide'); alertbox_clicked_button_id = pass_id; // 执行回调函数 if (typeof callback === 'function') { callback(alertbox_clicked_button_id); } } // 调用alertbox时传入回调,在交互完成后执行原生alert alertbox('Confirm to Cancel?', 'Confirmation', 'Yes', 'No', function(buttonId) { alert(buttonId); });
修改要点
- 将
alertbox_clicked_button_id声明移到代码最顶部,避免变量提升带来的潜在问题。 - 给
alertbox新增callback参数,用于接收模态框交互完成后的执行逻辑。 - 在按钮点击、自动关闭的函数中,调用传入的回调函数,把点击的按钮ID传递进去。
- 调用
alertbox时,传入回调函数,在里面执行原生alert(),确保在模态框交互完成后才触发。
内容的提问来源于stack exchange,提问作者soumitra
相关产品推荐
相关产品推荐

