我有以下示例:
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)到一个函数可能会导致性能问题。
让我们更改帖子示例。打开控制台并运行以下代码。
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/
如果我有一个Nodejs流,例如来自process.stdin或fs.createReadStream,我如何将其转换为RxJsObservable使用RxJs5流?我看到了RxJs-Node有一个fromReadableStream方法,但看起来它已经将近一年没有更新了。 最佳答案 对于任何正在寻找这个的人,根据Mark的建议,我为rxjs5改编了rx-nodefromStream实现。import{Observable}from'rxjs';//Adaptedfromhttps://github.com/Reac
我得到了一些在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
我想做什么我写了一个虚拟模块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'.我尝试解决的问题我知道模块本身的定
我知道在Java中有一个编译器可以在您编写错误代码时告诉您。但是Javascript不能那样工作,因为它没有编译器。但是,“linting”javascripts是编译代码的方式吗? 最佳答案 Linting正在解析代码以验证语法和格式是否正确并遵循良好实践。linter会告诉您缩进是否不正确,或者您是否应该在=运算符周围添加空格。如果您的代码包含众所周知的安全漏洞或代码异味,linter也会向您发出警告。编译是解析代码以验证语法是否正确并将代码转换为不同的语言(通常是更快的语言)。那么有什么区别呢?编译:语法验证代码转换为不同的语
如何在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
在ES5中我们都可以这样做:myClass.prototype.myMethod=(function(){returnfunction(){}})();我能用ES6类文字做同样的事情吗? 最佳答案 不,至少现在还没有。ES6类仅支持声明方法,因此任何不直接是方法的东西(包括间接评估为方法的东西,例如IIFE)仍必须使用原型(prototype)声明。但是,ES6类实际上与ES5构造函数一样工作,只是语法更简洁,所以您仍然可以这样做:classMyClass{constructor(){/*initialize*/}regularMe
有时我会看到大括号但有时不会。我搜索了很多但找不到正确的问题带花括号ng-src="{{imageSrc}}没有大括号ng-hide="imageSrc"我要问的是为什么我们不能将ng-hide写成ng-hide="{{imageSrc}}//doesn'tworkanyway为什么src和hide有两种不同的语法? 最佳答案 这仅取决于您使用的指令是“声明”的方式。如果指令有如下声明:scope:{ngHide:'='}那么,你不必使用双mustache,因为指令需要一个对象
在GitHubproject中我最近看到了这个函数声明:functionconfigureStore(onComplete:?()=>void){这个问号是关于什么的?我猜,onComplete是命名参数,获取函数调用。问号表示此参数可以是可选的,并且默认为“void”,这意味着与nil/null指针相同,这意味着此处分配的“无闭包”。我说得对吗? 最佳答案 差不多。()=>void是Flow对不返回任何内容的函数的注释(undefined,又名void0)。?MyType中的前导问号是Flow表达可空类型的方式。因此在这
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
当点为负时,我需要更改LineChart.js中的填充颜色(内部区域)。代码简单基础:$(document).ready(function(){varctx=$("#myChart").get(0).getContext("2d");vardata={labels:["January","February","March","April","May","June","July"],datasets:[{label:"MyFirstdat
如果我有一个Nodejs流,例如来自process.stdin或fs.createReadStream,我如何将其转换为RxJsObservable使用RxJs5流?我看到了RxJs-Node有一个fromReadableStream方法,但看起来它已经将近一年没有更新了。 最佳答案 对于任何正在寻找这个的人,根据Mark的建议,我为rxjs5改编了rx-nodefromStream实现。import{Observable}from'rxjs';//Adaptedfromhttps://github.com/Reac
我得到了一些在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
我想做什么我写了一个虚拟模块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'.我尝试解决的问题我知道模块本身的定
我知道在Java中有一个编译器可以在您编写错误代码时告诉您。但是Javascript不能那样工作,因为它没有编译器。但是,“linting”javascripts是编译代码的方式吗? 最佳答案 Linting正在解析代码以验证语法和格式是否正确并遵循良好实践。linter会告诉您缩进是否不正确,或者您是否应该在=运算符周围添加空格。如果您的代码包含众所周知的安全漏洞或代码异味,linter也会向您发出警告。编译是解析代码以验证语法是否正确并将代码转换为不同的语言(通常是更快的语言)。那么有什么区别呢?编译:语法验证代码转换为不同的语
如何在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
在ES5中我们都可以这样做:myClass.prototype.myMethod=(function(){returnfunction(){}})();我能用ES6类文字做同样的事情吗? 最佳答案 不,至少现在还没有。ES6类仅支持声明方法,因此任何不直接是方法的东西(包括间接评估为方法的东西,例如IIFE)仍必须使用原型(prototype)声明。但是,ES6类实际上与ES5构造函数一样工作,只是语法更简洁,所以您仍然可以这样做:classMyClass{constructor(){/*initialize*/}regularMe
有时我会看到大括号但有时不会。我搜索了很多但找不到正确的问题带花括号ng-src="{{imageSrc}}没有大括号ng-hide="imageSrc"我要问的是为什么我们不能将ng-hide写成ng-hide="{{imageSrc}}//doesn'tworkanyway为什么src和hide有两种不同的语法? 最佳答案 这仅取决于您使用的指令是“声明”的方式。如果指令有如下声明:scope:{ngHide:'='}那么,你不必使用双mustache,因为指令需要一个对象
在GitHubproject中我最近看到了这个函数声明:functionconfigureStore(onComplete:?()=>void){这个问号是关于什么的?我猜,onComplete是命名参数,获取函数调用。问号表示此参数可以是可选的,并且默认为“void”,这意味着与nil/null指针相同,这意味着此处分配的“无闭包”。我说得对吗? 最佳答案 差不多。()=>void是Flow对不返回任何内容的函数的注释(undefined,又名void0)。?MyType中的前导问号是Flow表达可空类型的方式。因此在这
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
当点为负时,我需要更改LineChart.js中的填充颜色(内部区域)。代码简单基础:$(document).ready(function(){varctx=$("#myChart").get(0).getContext("2d");vardata={labels:["January","February","March","April","May","June","July"],datasets:[{label:"MyFirstdat