如何垃圾收集外部 Javascript 负载?
How to Garbage Collect an external Javascript load?
给定一个装载机:
function loader(src, callback, fail) {
let s = document.head.appendChild(document.createElement('script'));
s.type = "text/javascript";
s.src = src;
s.onload = function() {
callback()
s.onload = null; //useful?
s = null; //or maybe this?
}
s.onerror = fail
}
有一行 s.onload = null
是否受益于 GC 释放一些内存?
是的,将属性设置为 null
确实有利于 GC。这样做会删除元素(包含在 DOM 中)对处理程序函数的引用,并且鉴于它可能是对该函数的唯一引用,它使该函数符合收集条件。但是,除非该函数是对保留大块内存的变量的闭包,否则这不太可能产生很大的影响。
您可能还想从回调中的 DOM 中删除 s
元素,使其也成为 garbage-collectable。
是的,s.onload = null
很有用并且会进行垃圾收集!
As of 2019, it is not possible to explicitly or programmatically trigger garbage collection in JavaScript。这意味着它会在需要时收集。
尽管 there is cases 设置为 null
可能会更早执行 GC(但不会触发它执行)。
截至 2012 年,所有现代浏览器都附带 mark-and-sweep garbage-collector.
它的工作原理是可达性:
Every object not reachable from the global context is deleted
周期性地 mark-and-sweep 发现并删除一个对象,当保存它的每个变量被 返回,重新分配或设置为 null.此外,现在不需要对任何变量无法访问的内容递归设置 null - 它无论如何都由 mark-and-sweep.
收集
现在到有问题的代码...
不需要 s = null
,因为当函数 returns、闭包从 call-stack 中移除并且 GC 负责处理 s
时变量无论如何都会被清除。
但是仍然有对脚本 onload
属性 的引用,因为 <script onload>
是 DOM 中 document.head
的子节点来自 window
!
callback
的内容可能可以访问,但在这里是不可能的。
如果浏览器足够智能,可以在内部设置 s.onload = null
会怎么样?我们先在第一个代码段中将其注释掉,然后在第二个代码段中取消注释...
function fetch(src, callback, fail) {
let s = document.head.appendChild(document.createElement('script'));
s.type = "text/javascript";
s.src = src;
s.onload = function() {
callback()
//s.onload = null; //useful?
}
s.onerror = fail
}
fetch("https://whosebug.com",
() => {console.log("Execute onload");},
() => {console.log("File not found");})
setTimeout(() => {
console.log(document.head.lastChild.onload)
},1000)
找到的文件执行出错,因为它不是Javascript.
onload
已执行但未删除。代码显示在日志中!
证明应该使用s.onload = null
行,像这样:
function fetch(src, callback, fail) {
let s = document.head.appendChild(document.createElement('script'));
s.type = "text/javascript";
s.src = src;
s.onload = function() {
callback()
s.onload = null; //useful!
}
s.onerror = fail
}
fetch("https://whosebug.com",
() => {console.log("Execute onload");},
() => {console.log("File not found");})
setTimeout(() => {
console.log(document.head.lastChild.onload)
},1000)
给定一个装载机:
function loader(src, callback, fail) {
let s = document.head.appendChild(document.createElement('script'));
s.type = "text/javascript";
s.src = src;
s.onload = function() {
callback()
s.onload = null; //useful?
s = null; //or maybe this?
}
s.onerror = fail
}
有一行 s.onload = null
是否受益于 GC 释放一些内存?
是的,将属性设置为 null
确实有利于 GC。这样做会删除元素(包含在 DOM 中)对处理程序函数的引用,并且鉴于它可能是对该函数的唯一引用,它使该函数符合收集条件。但是,除非该函数是对保留大块内存的变量的闭包,否则这不太可能产生很大的影响。
您可能还想从回调中的 DOM 中删除 s
元素,使其也成为 garbage-collectable。
是的,s.onload = null
很有用并且会进行垃圾收集!
As of 2019, it is not possible to explicitly or programmatically trigger garbage collection in JavaScript。这意味着它会在需要时收集。
尽管 there is cases 设置为 null
可能会更早执行 GC(但不会触发它执行)。
截至 2012 年,所有现代浏览器都附带 mark-and-sweep garbage-collector.
它的工作原理是可达性:
Every object not reachable from the global context is deleted
周期性地 mark-and-sweep 发现并删除一个对象,当保存它的每个变量被 返回,重新分配或设置为 null.此外,现在不需要对任何变量无法访问的内容递归设置 null - 它无论如何都由 mark-and-sweep.
收集现在到有问题的代码...
不需要 s = null
,因为当函数 returns、闭包从 call-stack 中移除并且 GC 负责处理 s
时变量无论如何都会被清除。
但是仍然有对脚本 onload
属性 的引用,因为 <script onload>
是 DOM 中 document.head
的子节点来自 window
!
callback
的内容可能可以访问,但在这里是不可能的。
如果浏览器足够智能,可以在内部设置 s.onload = null
会怎么样?我们先在第一个代码段中将其注释掉,然后在第二个代码段中取消注释...
function fetch(src, callback, fail) {
let s = document.head.appendChild(document.createElement('script'));
s.type = "text/javascript";
s.src = src;
s.onload = function() {
callback()
//s.onload = null; //useful?
}
s.onerror = fail
}
fetch("https://whosebug.com",
() => {console.log("Execute onload");},
() => {console.log("File not found");})
setTimeout(() => {
console.log(document.head.lastChild.onload)
},1000)
找到的文件执行出错,因为它不是Javascript.
onload
已执行但未删除。代码显示在日志中!
证明应该使用s.onload = null
行,像这样:
function fetch(src, callback, fail) {
let s = document.head.appendChild(document.createElement('script'));
s.type = "text/javascript";
s.src = src;
s.onload = function() {
callback()
s.onload = null; //useful!
}
s.onerror = fail
}
fetch("https://whosebug.com",
() => {console.log("Execute onload");},
() => {console.log("File not found");})
setTimeout(() => {
console.log(document.head.lastChild.onload)
},1000)