TOGOUTECH

javascript - 为什么我在 Angular JS 中得到两个方法调用?

coder 2024-05-16 原文

我有以下示例:

var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
  $scope.testMethod = function() {
    alert('hi');
  }
});
<!DOCTYPE html>
<html>

<head>
  <script data-require="[email protected]" data-semver="1.5.0" src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0/angular.min.js"></script>
</head>

<body ng-app="myApp">
  <div ng-controller="myCtrl">
    {{testMethod()}}
  </div>
</body>

</html>

我只在 View 模板中调用过一次该方法。但是为什么执行了两次呢?

最佳答案

当你在绑定(bind)表达式中使用函数时,Angular 将在每个 $digest 阶段重新计算表达式。这背后的原因是函数可以返回响应,但 Angular 无法知道结果是否不会在下一个函数调用中改变。

在这种情况下,Angular 确保它将以唯一可能的方式显示最新的正确的最新值 - 每次范围发生变化时调用该函数。

您会看到人们称此为“$digest phase”。它可能由于多种原因而发生。为了便于解释,我正在简化内容。如果您想了解更多信息,请阅读 https://docs.angularjs.org/guide/scope

作为一般规则 - 避免绑定(bind)到函数。相反,记住 $scope 变量中的函数响应并绑定(bind)到它。当项目中的绑定(bind)计数增加时,多次绑定(bind)到一个函数可能会导致性能问题。

编辑 - 对 sahbeewah 评论的回答(见下文)

让我们更改帖子示例。打开控制台并运行以下代码。

var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
  var i = 0;

  $scope.testMethod = function() {
    alert('hi');

    i++;
    return i; // Return a different value every time
  }
});
<!DOCTYPE html>
<html>

<head>
  <script data-require="[email protected]" data-semver="1.5.0" src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0/angular.js"></script>
</head>

<body ng-app="myApp">
  <div ng-controller="myCtrl">
    {{testMethod()}}
  </div>
</body>

</html>

出于示例目的,$scope.testMethod 在每次调用时返回不同的值很重要。

您会注意到以下几点:

  • “你好”提示会多次显示
  • 多次看到后会出现以下错误:

    Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!

所以,发生了什么事?每次我们在这里更改 $scope 状态时,angular 都会运行另一个摘要阶段,直到它“稳定”(没有更多更改)。连续 10 个 $digest 阶段有限制。

在线程帖子中,当连接 Controller 时,angular 调用 $digest,然后,因为我们更改了 $scope,它又调用了一个摘要。如果我们从代码中删除所有绑定(bind),则只会出现一个摘要。

我们可以很容易地检查这一点。从示例中删除 {{testMethod()}} 行,然后在 Angular 代码中放置一个断点:$digest,第 16700 行(angular 1.5.0) .
在这一行你会看到 if ((dirty || asyncQueue.length) && !(ttl--)) {

您的断点现在只会命中一次。让我们看看上面的 2 行。 Angular 团队在那里写了一条有趣的评论:

// `break traverseScopesLoop;` takes us to here

这是一个不言自明的注释,如果我们转到第 16629 行,我们会看到

do { // "while dirty" loop

代码中有一个名为“dirty”的变量,它创建了一个do...while 循环。虽然范围是(检测到更改),但您将留在这个循环中。更改是指通过任何类型的绑定(bind) ($watch) 以任何方式使用的任何范围变量的任何更改。

这就是为什么我们在这里有 2 个 $digest 阶段。

您可以找到 Angular 1.5 here .出于调试目的,我已切换到非缩小版本。

关于javascript - 为什么我在 Angular JS 中得到两个方法调用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36743457/

有关javascript - 为什么我在 Angular JS 中得到两个方法调用?的更多相关文章

  1. javascript - 如何将 Node 可读流转换为 RX 可观察流 - 2

    如果我有一个Nodejs流,例如来自process.stdin或fs.createReadStream,我如何将其转换为RxJsObservable使用RxJs5流?我看到了RxJs-Node有一个fromReadableStream方法,但看起来它已经将近一年没有更新了。 最佳答案 对于任何正在寻找这个的人,根据Mark的建议,我为rxjs5改编了rx-nodefromStream实现。import{Observable}from'rxjs';//Adaptedfromhttps://github.com/Reac

  2. javascript - 路径上特定点上的 SVG 标记中间 - 2

    我得到了一些在Canvas上生成路径的代码。路径对象看起来与此类似:<pathclass="link"d="M450,215.L265,236L225,236"style="stroke-width:1;"></path>在View中(a,b,c字母只是为了说明问题):我的问题是我想在线的中间画一些箭头(标记),在“a”到“b”之间,但是当我创建一个标记并执行标记中间属性时,它会在b点生成。我试图在a和b之间做一些点,但是marker-mid在那里和b点上做了箭头。来自WEBAPI文档:Themarker-midd

  3. javascript - 无法使用 Webpack、Typescript、自定义模块目录找到模块 - 2

    我想做什么我写了一个虚拟模块my-component,它基本上导出了一个类Something。我把它放在app/modules/中。现在我想使用app/app.js中的导入语法来访问它:import{Something}from'my-component';期望:根据我当前的Webpack配置(如下),我希望它能工作。实际:这会引发错误:ERRORin[default]/<project_dir>/app/app.ts:1:26Cannotfindmodule'my-component/Something'.我尝试解决的问题我知道模块本身的定

  4. javascript - linting 和编译有什么区别? - 2

    我知道在Java中有一个编译器可以在您编写错误代码时告诉您。但是Javascript不能那样工作,因为它没有编译器。但是,“linting”javascripts是编译代码的方式吗? 最佳答案 Linting正在解析代码以验证语法和格式是否正确并遵循良好实践。linter会告诉您缩进是否不正确,或者您是否应该在=运算符周围添加空格。如果您的代码包含众所周知的安全漏洞或代码异味,linter也会向您发出警告。编译是解析代码以验证语法是否正确并将代码转换为不同的语言(通常是更快的语言)。那么有什么区别呢?编译:语法验证代码转换为不同的语

  5. javascript - Chart.js 时间刻度 : set min and max on xAxes - 2

    如何在xAxes上设置最小值和最大值?它在yAxes上工作正常,但在xAxes上它没有显示任何行为。我的xAxes使用的是type:'time'。我的xAxis标签也使用了moment对象。但是当我删除类型时间并使用普通数字时它也不起作用。我使用的是Chart.js版本2.2.2。scales:{yAxes:[{ticks:{beginAtZero:false,}}],xAxes:[{type:'time',ticks:{min:moment(1471174953000),max:moment(1473853353000)}}]}Hereisthechart.jsTim

  6. javascript - ES6 类文字中的 IIFE - 2

    在ES5中我们都可以这样做:myClass.prototype.myMethod=(function(){returnfunction(){}})();我能用ES6类文字做同样的事情吗? 最佳答案 不,至少现在还没有。ES6类仅支持声明方法,因此任何不直接是方法的东西(包括间接评估为方法的东西,例如IIFE)仍必须使用原型(prototype)声明。但是,ES6类实际上与ES5构造函数一样工作,只是语法更简洁,所以您仍然可以这样做:classMyClass{constructor(){/*initialize*/}regularMe

  7. javascript - 何时使用大括号 - 2

    有时我会看到大括号但有时不会。我搜索了很多但找不到正确的问题带花括号ng-src="{{imageSrc}}没有大括号ng-hide="imageSrc"我要问的是为什么我们不能将ng-hide写成ng-hide="{{imageSrc}}//doesn'tworkanyway为什么src和hide有两种不同的语法? 最佳答案 这仅取决于您使用的指令是“声明”的方式。如果指令有如下声明:scope:{ngHide:'='}那么,你不必使用双mustache,因为指令需要一个对象

  8. javascript - Flow : "?() => void" 这个问号是什么意思 - 2

    在GitHubproject中我最近看到了这个函数声明:functionconfigureStore(onComplete:?()=>void){这个问号是关于什么的?我猜,onComplete是命名参数,获取函数调用。问号表示此参数可以是可选的,并且默认为“void”,这意味着与nil/null指针相同,这意味着此处分配的“无闭包”。我说得对吗? 最佳答案 差不多。()=>void是Fl​​ow对不返回任何内容的函数的注释(undefined,又名void0)。?MyType中的前导问号是Flow表达可空类型的方式。因此在这

  9. javascript - JavaScript 中的双重 for 循环 - 2

    varstartx=0,starty=0,endx=12,endy=100;for(startx;startx<=endx;startx+=1){for(starty;starty<=endy;starty+=1){console.log(startx,endx,starty,endy);}}预期输出:0,12,0,1000,12,1,1000,12,2,100...0,12,100,1001,12,0,1001,12,1,100...12,12,100,100;EOOChrome39+上的输出0,12,0,1000,12,1,1000,12,2,100...0,12,10

  10. javascript - Chart.js Line,负点的不同填充颜色 - 2

    当点为负时,我需要更改LineChart.js中的填充颜色(内部区域)。代码简单基础:$(document).ready(function(){varctx=$("#myChart").get(0).getContext("2d");vardata={labels:["January","February","March","April","May","June","July"],datasets:[{label:"MyFirstdat

随机推荐

  1. javascript - 如何将 Node 可读流转换为 RX 可观察流 - 2

    如果我有一个Nodejs流,例如来自process.stdin或fs.createReadStream,我如何将其转换为RxJsObservable使用RxJs5流?我看到了RxJs-Node有一个fromReadableStream方法,但看起来它已经将近一年没有更新了。 最佳答案 对于任何正在寻找这个的人,根据Mark的建议,我为rxjs5改编了rx-nodefromStream实现。import{Observable}from'rxjs';//Adaptedfromhttps://github.com/Reac

  2. javascript - 路径上特定点上的 SVG 标记中间 - 2

    我得到了一些在Canvas上生成路径的代码。路径对象看起来与此类似:<pathclass="link"d="M450,215.L265,236L225,236"style="stroke-width:1;"></path>在View中(a,b,c字母只是为了说明问题):我的问题是我想在线的中间画一些箭头(标记),在“a”到“b”之间,但是当我创建一个标记并执行标记中间属性时,它会在b点生成。我试图在a和b之间做一些点,但是marker-mid在那里和b点上做了箭头。来自WEBAPI文档:Themarker-midd

  3. javascript - 无法使用 Webpack、Typescript、自定义模块目录找到模块 - 2

    我想做什么我写了一个虚拟模块my-component,它基本上导出了一个类Something。我把它放在app/modules/中。现在我想使用app/app.js中的导入语法来访问它:import{Something}from'my-component';期望:根据我当前的Webpack配置(如下),我希望它能工作。实际:这会引发错误:ERRORin[default]/<project_dir>/app/app.ts:1:26Cannotfindmodule'my-component/Something'.我尝试解决的问题我知道模块本身的定

  4. javascript - linting 和编译有什么区别? - 2

    我知道在Java中有一个编译器可以在您编写错误代码时告诉您。但是Javascript不能那样工作,因为它没有编译器。但是,“linting”javascripts是编译代码的方式吗? 最佳答案 Linting正在解析代码以验证语法和格式是否正确并遵循良好实践。linter会告诉您缩进是否不正确,或者您是否应该在=运算符周围添加空格。如果您的代码包含众所周知的安全漏洞或代码异味,linter也会向您发出警告。编译是解析代码以验证语法是否正确并将代码转换为不同的语言(通常是更快的语言)。那么有什么区别呢?编译:语法验证代码转换为不同的语

  5. javascript - Chart.js 时间刻度 : set min and max on xAxes - 2

    如何在xAxes上设置最小值和最大值?它在yAxes上工作正常,但在xAxes上它没有显示任何行为。我的xAxes使用的是type:'time'。我的xAxis标签也使用了moment对象。但是当我删除类型时间并使用普通数字时它也不起作用。我使用的是Chart.js版本2.2.2。scales:{yAxes:[{ticks:{beginAtZero:false,}}],xAxes:[{type:'time',ticks:{min:moment(1471174953000),max:moment(1473853353000)}}]}Hereisthechart.jsTim

  6. javascript - ES6 类文字中的 IIFE - 2

    在ES5中我们都可以这样做:myClass.prototype.myMethod=(function(){returnfunction(){}})();我能用ES6类文字做同样的事情吗? 最佳答案 不,至少现在还没有。ES6类仅支持声明方法,因此任何不直接是方法的东西(包括间接评估为方法的东西,例如IIFE)仍必须使用原型(prototype)声明。但是,ES6类实际上与ES5构造函数一样工作,只是语法更简洁,所以您仍然可以这样做:classMyClass{constructor(){/*initialize*/}regularMe

  7. javascript - 何时使用大括号 - 2

    有时我会看到大括号但有时不会。我搜索了很多但找不到正确的问题带花括号ng-src="{{imageSrc}}没有大括号ng-hide="imageSrc"我要问的是为什么我们不能将ng-hide写成ng-hide="{{imageSrc}}//doesn'tworkanyway为什么src和hide有两种不同的语法? 最佳答案 这仅取决于您使用的指令是“声明”的方式。如果指令有如下声明:scope:{ngHide:'='}那么,你不必使用双mustache,因为指令需要一个对象

  8. javascript - Flow : "?() => void" 这个问号是什么意思 - 2

    在GitHubproject中我最近看到了这个函数声明:functionconfigureStore(onComplete:?()=>void){这个问号是关于什么的?我猜,onComplete是命名参数,获取函数调用。问号表示此参数可以是可选的,并且默认为“void”,这意味着与nil/null指针相同,这意味着此处分配的“无闭包”。我说得对吗? 最佳答案 差不多。()=>void是Fl​​ow对不返回任何内容的函数的注释(undefined,又名void0)。?MyType中的前导问号是Flow表达可空类型的方式。因此在这

  9. javascript - JavaScript 中的双重 for 循环 - 2

    varstartx=0,starty=0,endx=12,endy=100;for(startx;startx<=endx;startx+=1){for(starty;starty<=endy;starty+=1){console.log(startx,endx,starty,endy);}}预期输出:0,12,0,1000,12,1,1000,12,2,100...0,12,100,1001,12,0,1001,12,1,100...12,12,100,100;EOOChrome39+上的输出0,12,0,1000,12,1,1000,12,2,100...0,12,10

  10. javascript - Chart.js Line,负点的不同填充颜色 - 2

    当点为负时,我需要更改LineChart.js中的填充颜色(内部区域)。代码简单基础:$(document).ready(function(){varctx=$("#myChart").get(0).getContext("2d");vardata={labels:["January","February","March","April","May","June","July"],datasets:[{label:"MyFirstdat