XMLHttpRequest对象何时会被回收?
XMLHttpRequest 对象的垃圾回收疑问解答
先看你提供的代码和场景:
<script> function ajax_async(method, url, body, cb) { var r = new XMLHttpRequest(); r.open(method, url, true); r.onreadystatechange = cb; r.send(body); } ajax_async('GET', '/sleep.php', null, function() { if(this.readyState==4) alert('123'); }); </script>
补充场景:
sleep.php仅会休眠10秒后返回结果。
下面针对你的问题逐一解释:
为什么局部变量 r 对应的XHR对象在请求运行时没被回收?
没错,r 是 ajax_async 函数的局部变量,函数执行结束后外部确实无法直接访问它,但有两个关键因素让这个XHR对象保持可达:
- 回调函数的间接引用:你给XHR对象绑定了
onreadystatechange回调,而回调里的this指向该XHR对象——这意味着回调函数本身持有对XHR对象的引用,只要回调还可能被触发,这个引用就会存在。 - 浏览器内部的引用:在XHR请求处于活跃状态(readyState <4)时,浏览器会在内部维持对该对象的引用,确保请求能正常完成,并且能触发对应的状态变化事件。
只要对象处于可达状态(有任何引用指向它),JS的垃圾回收器就不会回收它。
当 readyState==4 后,该对象会被回收吗?
满足条件的话会被回收,但不是立刻。当 readyState 变为4(请求完成):
- 首先浏览器会释放它内部对该XHR对象的引用;
- 其次,你的回调函数执行完毕后,如果没有其他代码再持有对这个XHR对象的引用(比如没把它赋值给全局变量、闭包变量或者持久DOM元素的属性),那么这个XHR对象就会变成不可达状态。
此时,垃圾回收器在下一次运行时(比如引擎空闲阶段)就会标记这个对象为垃圾并回收它。
如果不会,它何时会被回收?
只有当所有指向该XHR对象的引用都被清除时,它才会被回收:
- 如果你在回调里把XHR对象保存到了某个持久化的地方(比如
window.xhr = this),那它会一直存在,直到你手动清除这个引用(比如window.xhr = null); - 如果没有额外的引用,那么在浏览器内部引用释放、回调执行完成且没有闭包残留引用后,垃圾回收器会按照自身的策略(比如标记清除、分代回收)在合适的时机回收它。
是否有相关规范明确说明 readyState==4 表示“可回收”,而其他状态则不可?
规范不会直接用“可回收”这种表述,但从XMLHttpRequest的官方规范设计逻辑可以推导出来:
- 当XHR处于未完成状态(readyState <4)时,规范要求浏览器必须维持对象的生命周期,保证请求能按阶段触发状态变化事件,因此浏览器会持有引用,对象处于可达状态;
- 当readyState变为4后,请求的所有生命周期事件都已触发完成,规范不再要求浏览器维持该对象的引用,此时只要用户代码中没有保留引用,对象就会进入可回收的不可达状态。
垃圾回收的核心规则始终是对象的可达性,规范只是定义了XHR对象的生命周期边界,间接影响了它的回收时机。
内容的提问来源于stack exchange,提问作者firk
相关产品推荐
相关产品推荐

