如何GC加载外部Javascript?

时间:2019-07-04 21:46:49

标签: javascript performance garbage-collection dynamic-script-loading

在加载外部脚本之后执行class ViewController: UIViewController { override func viewDidLoad() { firstButton.tag = 1 secondButton.tag = 2 thirdButton.tag = 3 } func goToNextVC(buttonTag: Int) { let vc = SecondVC() vc.buttonTag = buttonTag self.navigationController.push(vc, animated: true) } // action for all buttons if he just only send tag func buttonsDidTap(_ sender: Any) { goToNextVC(buttonTag: sender.tag) } } 是否有好处或问题?
好处可能是GC释放了一些内存?

在som编辑后,以下代码应足以引起注意。
查看评论。

class SecondVC: UIViewController {

    var buttonTag: Int?

    override func viewDidLoad() {

        if buttonTag != nil {
            switch buttonTag:
            case 0:
            // ...
        }
    }
}

我不知道Javascript是如何做到的,或者它是否可以免费供浏览器使用,但是如果在将其插入dom后在闭包中保留了很多大脚本,则应该通过垃圾回收将其删除。手动收集器(如果不是自动完成的话(最好需要引用w3c才能知道所有兼容的浏览器都可以)

2 个答案:

答案 0 :(得分:1)

是的,将属性设置为null确实有益于GC。这样做会删除元素(包含在DOM中)对处理程序函数的引用,并且鉴于它可能是对该函数的唯一引用,因此它使该函数有资格进行收集。但是,除非该函数是对保留大量内存的变量的封闭,否则不太可能产生很大影响。

您可能还想从回调中的DOM中删除s元素,使其也可以垃圾回收。

答案 1 :(得分:0)

是的,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垃圾收集器。
它基于 reachability

的原理工作
  

从全局上下文无法访问的每个对象都将被删除

标记扫掠会在返回,重新分配或将其设置为null 时定期发现并删除对象。同样,如今也不需要对无法通过任何变量访问的内容进行递归设置为null-无论如何,它都是通过 mark-and-sweep 收集的。

现在转到有问题的代码...

在第一行中,我们看到sdocument.head的子项指向相同的document.createElement('script')。当函数返回并从调用堆栈中删除闭包时,其声明的变量s也将被删除。尽管s引用的值仍然不是垃圾回收,因为它仍然可以通过document到达。

所以..不需要s = null,因为删除变量后指针仍然会清除,但是仍然引用脚本onload属性,因为<script onload>是孩子从document.head可以访问的DOM 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://stackoverflow.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://stackoverflow.com", 
       () => {console.log("Execute onload");}, 
       () => {console.log("File not found");})

setTimeout(() => {
    console.log(document.head.lastChild.onload)
},1000)