【问题标题】:Do I need to destroy local controller variables when directive is destroyed?当指令被销毁时,我是否需要销毁本地控制器变量?
【发布时间】:2016-07-16 09:25:04
【问题描述】:

我最近一直在编写许多 Angular 指令,并且一直在阅读有关在指令被销毁时必须手动删除您在指令中创建的内容的信息。不过还是有点不清楚。

我知道 $scope 上的任何东西都会被销毁,但是在指令的控制器中创建的局部变量、数组、函数等呢?

这是我的应用程序中的一些示例代码

angular.module('myModule').controller('s4pFileUploadCtrl', function($scope, $element, $attrs, FileUploader){

    var self = this;

    self.uploader = new FileUploader({
        settings: {}
    });

    // Elsewhere in the controller
    var reader = new FileReader();      
    reader.onload = onLoadFile;

    function onLoadFile(event) {
        var img = new Image();
        img.onload = onLoadImage;
    }

});

这是一个人为的并且非常精简的功能,但是我需要在 $scope 销毁事件中删除上传器吗?我需要对 FileReader 做任何事情吗?它与 onLoadFile 事件相关联?

任何帮助将不胜感激。我已经阅读了大量关于清理指令的文章,但没有一篇提到过这样的事情。

【问题讨论】:

    标签: javascript angularjs angularjs-scope angular-directive


    【解决方案1】:

    这里是a great article,了解更多关于 javascript 内存管理和垃圾收集的背景知识。基本上,它的工作原理是这样的......

    Javascript 内存管理 - 垃圾收集器

    创建时会为对象分配内存:

    var o = {iThink: 'thereforeIAm'}; // memory allocated for an object and a string
    

    然后您可能会从内存中的位置读取 console.log(o.iThink)'thereforeIAm' 并打印到控制台。

    如果您想创建一个新字符串并丢失了{iThink: 'thereforeIAm'} 对象的需求,您可以决定覆盖o 而不是引入新变量,例如:

    o = 'helloImANewString';
    

    幸运的是,引用(或缺少引用)在内部向 javascript 的垃圾收集器发送了一条明确的消息,说明一块(有限)内存是否应该保持分配或释放以执行其他任务。在这种情况下,不会保留对先前为 {iThink: 'thereforeIAm'} 分配的对象和字符串的引用,并且可能会释放相应的内存(即“垃圾收集”)。

    重要的是,请注意垃圾收集发生在内部。您不必为此编写任何代码。您只需要关心o 的值,而垃圾收集器可以从剩余的参考中推断出需要,或多或少

    Angular 内存管理 - $scope.$destroy

    ​​>

    很遗憾,与$scope 删除相关的清理任务无法由javascript 垃圾收集器推断仅基于引用;需要额外的代码。

    这是因为 $scope 对象体现了一个比任何 ol' javascript 对象都复杂的概念。特别是,当某个$scope 对象在您的应用程序中没有任何用途时,对于之前使用$scope.$watch 方法注册的任何关联$$watchers 并且没有使用,没有使用也必须保持对于“儿童”$scope 对象,也必须保留。 javascript 垃圾收集器无法从简单的引用删除中推断出这种关系,例如:

    $scope = null; // $scope object will be garbage collected, but nothing else
    

    换句话说,垃圾收集器必须被告知要做什么,这正是$scope.$destroy method 所做的。请特别注意以下几行:

    $scope.$parent = $scope.$$nextSibling = $scope.$$prevSibling = $scope.$$childHead =
        $scope.$$childTail = $scope.$root = $scope.$$watchers = null;
    

    现在回答你的问题

    我知道放置在 $scope 上的任何东西都会被销毁,但是在指令的控制器中创建的局部变量、数组、函数等呢?

    可以,但不是直接通过 $destroy 方法

    当一个函数被调用时,为内部作用域对象分配的内存将只在调用生命周期之后的引用范围内保持分配。

    实际上,在您的控制器示例中,无论$scope 是否为$destroy'ed,在运行控制器功能后,都根本没有对reader 的引用。但是,即使您确实将它附加到$scope,就像您对uploader 所做的那样,唯一剩余的对它的引用来自对$scope 的这种附加。因此,对$scope.$destroy() 的任何调用都会删除对uploader 的最后一个引用(通过删除对$scope 的任何引用)并使其符合javascript 垃圾回收条件。

    【讨论】:

    • 谢谢,这是一个非常全面的答案。我只是想确定一件事......当你说我将上传者附加到 $scope 时,我实际上将它附加到 self ,它等于“this”,例如控制器本身。我特别想知道连接到控制器的东西会发生什么。我假设从文档中删除相关指令时控制器本身被破坏,但我想确定一下。基本上,听起来我在这里什么都不用做。
    • 通过将uploader 附加到this,实际上您确实间接地将它附加到$scope,因为this(即控制器)附加到$scope。是的,对控制器的引用被销毁了,你不需要在这里做任何事情。
    • 其实“尤其是这些行”与垃圾回收无关。评论清楚地写着“禁用”,而不是清理。它也会与你自己的例子相矛盾。
    • @zeroflagL 这是一个很好的观点,感谢您的关注。更改为正确的行
    【解决方案2】:

    当 $scope.$destroy() 被执行时,它会移除所有通过 $on 在那个 $scope 上注册的监听器。

    它不会删除 DOM 元素或任何附加的事件处理程序。

    如果在元素上调用 element.remove(),那么它的所有子元素都将从 DOM 中删除,所有事件处理程序都会通过 element.on 附加,但它不会破坏与元素关联的 $scope。

    【讨论】:

    • 你没有回答问题。
    猜你喜欢
    • 2011-02-23
    • 1970-01-01
    • 2017-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-05
    相关资源
    最近更新 更多