Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/384.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript Angular JS$compile服务导致$watch内存泄漏_Javascript_Angularjs_Memory Leaks - Fatal编程技术网

Javascript Angular JS$compile服务导致$watch内存泄漏

Javascript Angular JS$compile服务导致$watch内存泄漏,javascript,angularjs,memory-leaks,Javascript,Angularjs,Memory Leaks,我猜由于误用以下代码导致内存泄漏,我不明白为什么,我录制了简短的屏幕广播来演示问题,您可以在这里找到: 下面是失败的代码,它只是动态编译存储在名为content的变量中的html,但是一旦您开始通过textarea更改content变量,代码就会开始创建$watch'es,一旦您增加绑定量,情况就会变得更糟,对于每个绑定,Angular都会创建新的作用域(这显然是正确的),但它不会删除旧的作用域,而是将它们保存在内存中 <!DOCTYPE html> <html ng-app=

我猜由于误用以下代码导致内存泄漏,我不明白为什么,我录制了简短的屏幕广播来演示问题,您可以在这里找到:

下面是失败的代码,它只是动态编译存储在名为
content
的变量中的html,但是一旦您开始通过textarea更改
content
变量,代码就会开始创建$watch'es,一旦您增加绑定量,情况就会变得更糟,对于每个绑定,Angular都会创建新的作用域(这显然是正确的),但它不会删除旧的作用域,而是将它们保存在内存中

<!DOCTYPE html>
<html ng-app="plunker">

  <head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <script data-require="angular.js@1.3.x" src="https://code.angularjs.org/1.3.15/angular.js" data-semver="1.3.15"></script>
      <script>
          var app = angular.module('plunker', []);

          app.controller('MainCtrl', function($scope) {
              $scope.name = 'World';
          });

          app.directive('compile', function($compile) {
              return {
                  restrict: 'A',
                  link: function(scope, elem, attrs) {
                      scope.$watch(attrs.compile, function(newVal) {
                          // create a span (an inline element) so we have an actual DOM node to
                          // set the innerHTML of.
                          var newElem = document.createElement('span');

                          newElem.innerHTML = newVal;

                          // clear out the contents of this element
                          elem[0].innerHTML = '';

                          // and replace it with the raw (uncompiled) node
                          elem[0].appendChild(newElem);

                          // now the node is in the DOM so we can compile it
                          // but we want to use a try..catch because the user
                          // might be in the middle of typing a new expression,
                          // but the syntax right now is not valid so the
                          // expression parser will throw an error.
                          try {
                              // compile the node in the DOM with the existing scope
                              $compile(newElem)(scope);
                          } catch(e) { /* don't need to do anything here */
                          }
                      });
                  }
              };
          });
      </script>
  </head>

  <body ng-controller="MainCtrl" ng-init="variable = 3; content = '{{ variable }}'">
    <div>
      The value of $scope.variable === "{{ variable }}"
    </div>
    <div>
      The value of $scope.content === "{{ content }}"
    </div>
    <br>
    <div>
    The value of $scope.content is <b>ng-model</b>'ed via the following textarea:<br>
    </div>

    <textarea rows="3" ng-model="content"></textarea>

    <div style="border: 1px solid black">
      Instead of rendering the value of the $scope.content field which is currently equal to "{{ content }}" I need to render compiled and evaluated value which should be equal to "{{ variable }}"
    </div>

    <hr>

    <p>Look! It works: <span compile="content"></span></p>
  </body>

</html>

安古拉斯普朗克
文件。写(“”);
var app=angular.module('plunker',[]);
应用程序控制器('MainCtrl',函数($scope){
$scope.name='World';
});
app.directive('compile',function($compile){
返回{
限制:“A”,
链接:功能(范围、要素、属性){
作用域$watch(attrs.compile,函数(newVal){
//创建一个span(内联元素),这样我们就有了一个实际的DOM节点
//设置的innerHTML。
var newElem=document.createElement('span');
newElem.innerHTML=newVal;
//清除此元素的内容
元素[0]。innerHTML='';
//并将其替换为原始(未编译)节点
元素[0]。追加子元素(newElem);
//现在节点位于DOM中,因此我们可以编译它
//但是我们想使用try..catch,因为用户
/可能在键入一个新表达式的中间,
//但是现在的语法无效,所以
//表达式分析器将抛出一个错误。
试一试{
//使用现有范围编译DOM中的节点
$compile(newElem)(范围);
}捕获(e){/*在这里不需要做任何事情*/
}
});
}
};
});
$scope.variable的值==“{{variable}”
$scope.content的值==“{{content}”

$scope.content的值通过以下文本区域显示为ng-model:
与其呈现当前等于“{content}”的$scope.content字段的值,我需要呈现应等于“{variable}”的编译和计算值
看!它的工作原理是:


好吧,很抱歉,我不知道内存泄漏有多严重!(这是我Lu4使用的指令)

我相信我现在已经排除了漏洞,清理得更好了。每次重新编译时,我都会创建一个新的子范围,并首先销毁旧的子范围。根据,我确保在清除DOM元素之前销毁范围


没有一个合理的方法来做你正在尝试的事情。即使是使用
element.html()
而不是
elem[0].appendChild()
的官方文档也显示了这种行为,尽管看起来他们的方法可能不那么严厉。。。。你用什么优秀的devtools扩展来显示视频右侧的性感计数器?这算什么?你不应该道歉,我很感谢你以前的帮助,这次也很有帮助!很好的视频,我有一种直觉,它必须是范围的问题,但在我这方面,它是近凌晨5点,所以我只是问了一个问题,并去睡觉
app.directive('compile', function($compile) {
  return {
    restrict: 'A',
    link: function(scope, elem, attrs) {
      var prevScope;
      scope.$watch(attrs.compile, function(newVal, oldVal) {
        // create a span (an inline element) so we have an actual DOM node to
        // set the innerHTML of.
        var newElem = document.createElement('span');
        newElem.innerHTML = newVal;
        // clean up first
        if (prevScope) {
          prevScope.$destroy();
          prevScope = null;
        }
        // clear out the contents of this element
        elem.empty();
        // and replace it with the raw (uncompiled) node
        elem[0].appendChild(newElem);
        // now the node is in the DOM so we can compile it
        // but we want to use a try..catch because the user
        // might be in the middle of typing a new expression,
        // but the syntax right now is not valid so the
        // expression parser will throw an error.
        try {
          // compile the node in the DOM with a child of the existing scope
          prevScope = scope.$new();
          $compile(newElem)(prevScope);
        } catch (e) { /* don't need to do anything here */ }
      });
    }
  }
});