JavaScript委托用法:XMLHttpRequest AJAX请求回调提前执行问题求解
核心问题原因
你遇到的执行顺序问题本质是JavaScript中函数引用和函数调用的语法差异,和C#的委托绑定逻辑有明显区别:
- 当你写
函数名()时,JS会立即执行这个函数,返回函数的执行结果 - 当你只写
函数名时,才是传递函数本身的引用,等价于C#里的委托引用
你原代码里的httpxml.onreadystatechange = PopulateProductCode(httpxml); 实际是把PopulateProductCode执行后的返回值(你的函数没有return语句,所以返回值是undefined)绑定给了事件,所以会在代码运行到这行时立即触发函数执行,事件后续触发时也没有对应处理逻辑可以运行。
而你后来写的匿名函数写法,是把整个匿名函数对象作为引用赋值给事件,没有加括号执行,所以只有事件实际触发时才会运行内部逻辑,这就是两种写法的本质差异。
独立函数绑定实现方案
你要把处理逻辑放在独立函数中,有两种常用实现方式:
方案1:直接绑定函数引用,用this访问XHR实例
onreadystatechange事件触发时,处理函数内部的this默认指向当前XMLHttpRequest实例,直接把函数名(不带括号)赋值给事件即可:
// 绑定部分代码 httpxml.onreadystatechange = PopulateProductCode; // 独立处理函数 function PopulateProductCode() { try { if (this.readyState == 4 && this.status == 200) { const data = this.responseText; alert(data); // 后续处理逻辑写在这里即可 } } catch (e) { alert(e.message); } }
方案2:匿名函数包裹传参
如果有额外参数需要传递给处理函数,可以用匿名函数做一层包装,在事件触发时才调用你的独立处理函数:
// 绑定部分代码 httpxml.onreadystatechange = function() { // 这里可以传入自定义参数 PopulateProductCode(httpxml); }; // 独立处理函数 function PopulateProductCode(httpxml) { try { if (httpxml.readyState == 4 && httpxml.status == 200) { const data = httpxml.responseText; alert(data); } } catch (e) { alert(e.message); } }
额外优化建议
你现有代码里的httpxml、elProductCode、ProductCode等变量都没有用var/let/const声明,会自动成为全局变量,容易引发变量污染和冲突,建议都补充变量声明。
内容的提问来源于stack exchange,提问作者Mark Roworth
相关产品推荐
相关产品推荐

