我有以下示例:
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/
我有一个自定义事件core-transitionend(实际上由Polymer触发),我可以使用document.addEventListener()设置事件处理程序.但在AngularJS中执行此操作的最佳做法是什么?或者,我可以在DOM中明确设置一个处理程序,即,但是如何在AngularJS中定义这个函数呢? 最佳答案 参见thisfiddle,我在这里创建了一个自定义指令,它将事件绑定(bind)到元素,angular.module('HelloApp',[]).directive('customDir',function
在某些情况下,提倡组合而不是继承。我看到这种情况在Ruby和Javascript社区中越来越多地发生。组合听起来很像多重继承。我什至在一些Ruby实现的内部读到过,模块组合是带有少量语法糖的多重继承。是一样的吗?如果不是,它与多重继承有何不同? 最佳答案 这取决于您所说的“多重继承”和“组合”是什么意思。如果组合和继承都只是意味着添加到对象响应的消息列表中,那么它们在定义上是相等的。假设类很简单virtualtables方法,并且语言中的每个对象都是由对类和一些数据的引用定义的。如果对象通过调用与其类关联的方法查找函数来响应消息,并
在AngularJS应用程序中,我对服务器url进行$http.post调用。此url的成功响应是30x重定向,我的问题是$http.post严格遵循此重定向并在成功回调中返回最终调用的结果。我想拦截此重定向并手动将用户重定向(更改浏览器url)到最终页面。可能吗? 最佳答案 根据docs,$http服务是一个核心Angular服务,它通过浏览器的XMLHttpRequest对象或通过JSONP促进与远程HTTP服务器的通信。了解这一点,并了解XMLHttpRequest的规范,拦截重定向可能是不可能的。W3CspecforXMLH
转发似乎在Meteor中,我们无法调用服务器端路由来将文件呈现到页面,而无需从我们的正常工作流程中进行某种变通,根据我所阅读的有关服务器端路由的内容。我希望我在这一点上是错的,并且有一种简单的方法可以实现我想要做的事情......**抱歉,如果这有点长,但我认为在这种情况下提供更多的背景和上下文是必要的**软件/版本我正在使用最新的IronRouter1.*和Meteor1.*并且开始时,我只使用帐户密码。背景/语境我有一个onBeforeAction,它只是根据用户是否登录将用户重定向到欢迎页面或主页:两者/routes.jsRouter.onBeforeAction(functio
UPDATEDDEMO工作得很好,除了当我改变时背景图像正在调整大小:background-size:20px20px;是否可以保持原图大小,让背景图重叠(隐藏图片超出左上框(20px20px)的部分)?B计划是在设置的base64图像内容中用JS裁剪图像... 最佳答案 使用只有左边框和上边框的svg图像可能就是您要找的东西?检查片段,或这个jsfiddle(fiddle包含放大/缩小网格的按钮):body{background:url('http://testbed.nicon.nl/img/_FBs3b.svg')repeat
基本上,我的模板中有这段代码:{{entry.school}}{{entry.school}}...如您所见,我试图在entry.url不为空时显示可点击的URL,否则显示纯文本。它工作正常,但看起来很丑陋。有没有更优雅的解决方案?我能想到的另一种方法是使用ng-if:{{entry.school}}{{entry.school}}但是我会重复几乎相同的比较两次,这看起来更糟。你们会如何处理这个问题? 最佳答案 你可以试试。hellohello但是ngSwitch您正在使用的应该没问题。
我正在使用Angular-ui弹出一个带有表单的模式。我的代码是:app.controller('NewCaseModalCtrl',['$http','$scope','$modal',function($http,$scope,$modal,$log){$scope.items=['item1','item2','item3'];$scope.open=function(size){varmodalInstance=$modal.open({templateUrl:'modal-new-case.html',controller:'ModalInstanceCtrl',size:s
我写了atexteditorinJavaScriptthatdrawsdirectlytoaCanvaselement(出于各种原因,但我的主要原因是我可以将该Canvas作为纹理贴在WebGL网格上)。令人高兴的是,实现我发现的任何内容可编辑解决方案都更容易。我很早就注意到的一件事是使用en-USQWERTY以外的键盘布局的人提示某些键显示不正确的字母。在对Windows的语言设置和屏幕键盘进行了一些摆弄之后,我创建了一个基于代码页的解决方案,该解决方案将keyCode直接映射到不同语言环境的字符串,而不是仅仅假设“没有修饰键的keyCode51是数字3”。因为它不是,所以在某些键盘
我如何使用非唯一键索引数组。我尝试使用lodashindexBy,但它没有给出预期的结果。varkeys=[{'dir':'left','code':97},{'dir':'left','code':100},{'dir':'right','code':50},{'dir':'right','code':51}];vara=_.indexBy(keys,'dir');结果:{left:{dir:'left',code:100},right:{dir:'right',code:51}}预期结果:{left:[{dir:'left',code:100},{'dir':'left','cod
一句话类似:Loremipsum+dolor++sitamet.我想匹配+dolor但不是++sit.我可以通过回顾来做到这一点,但是因为JavaScript不支持它我正在努力为它建立一个模式。到目前为止,我已经尝试过:(?:\+(.+?))(?=[\s\.!\!])-butitmatchesbothwords(?:\+{1}(.+?))(?=[\s\.!\!])-thesamehere-bothwordsarematched令我惊讶的是这样的模式:(?=\s)(?:\+(.+?))(?=[\s\.!\!])不匹配任何东西。我以为我可以欺骗它并使用\s或者稍后还有^在+之前签名,但它似