我发现这段代码片段是有人为bootstrap模态编写的angular指令的一部分。
//Update the visible value when the dialog is closed
//through UI actions (Ok, cancel, etc.)
element.bind("hide.bs.modal", function () {
scope.modalVisible = false;
if (!scope.$$phase && !scope.$root.$$phase)
scope.$apply();
});
我明白这部分是针对双向绑定的后半部分,我们绑定到hide.bs.modal事件并在UI更改时更新模态。
我只是想知道为什么在调用apply之前检查范围和rootScope的$$阶段的人?
我们不能直接打电话申请吗?
这里的$$阶段是什么?
我试了很多次,找不到任何好的解释。
修改
我在哪里看到了这个例子: Simple Angular Directive for Bootstrap Modal
答案 0 :(得分:45)
$$phase
是一个标志设置,而角度是$digest
周期。
有时(在极少数情况下),您希望在执行$$phase
之前检查范围$apply
。如果您在$apply
:
$digest
,则会出错
错误:$申请已在进行中
答案 1 :(得分:35)
Davin完全正确,它是在消化周期中角度设定的旗帜。
但请勿在代码中使用它。
我最近有机会向Misko(有角度的作者)询问关于$$阶段,他说永远不会使用它;它是摘要周期的内部实现,并不是未来的安全。
为确保您的代码在将来继续有效,他建议在$ timeout内包装您想要“安全申请”的内容
$timeout(function() {
// anything you want can go here and will safely be run on the next digest.
})
当您在摘要周期中有回调或其他可能解决的事情时(但并非总是如此),这会出现很多事情
以下是我处理谷歌图书馆时的一个示例代码段:(其余的服务来自此处。)
window.gapi.client.load('oauth2', 'v2', function() {
var request = window.gapi.client.oauth2.userinfo.get();
request.execute(function(response) {
// This happens outside of angular land, so wrap it in a timeout
// with an implied apply and blammo, we're in action.
$timeout(function() {
if(typeof(response['error']) !== 'undefined'){
// If the google api sent us an error, reject the promise.
deferred.reject(response);
}else{
// Resolve the promise with the whole response if ok.
deferred.resolve(response);
}
});
});
});
请注意,$ timeout的延迟参数是可选的,如果未设置则默认为0($timeout调用$browser.defer defaults to 0 if delay isn't set)
有点不直观,但这是写Angular的人的答案,所以这对我来说已经足够了!
答案 2 :(得分:6)
在该示例中,元素绑定将从非角度事件执行。在大多数情况下,只需在不检查阶段的情况下调用$apply()
即可。
但是,如果查看其余代码,则会有一个名为$scope
的{{1}}函数。此函数调用非角度代码,这可能导致“hide.bs.modal”事件触发。如果事件通过此路由触发,则调用堆栈位于showModal()
内。
因此,这个事件确实属于一个罕见的函数,它将从角度管理代码和非角度代码中调用。在这种情况下检查$digest
是必要的,因为您不知道事件是如何产生的。如果将$$phase
设置为某个值,则摘要循环将完成,并且不需要调用$$phase
。
此模式通常称为"safe apply"。
答案 3 :(得分:2)
我的理解是在消化或应用范围时使用是很好的。如果它是真实的,则意味着目前正在进行$ digest或$ apply阶段。如果你得到相关的错误,你可以做$ scope。$$阶段|| $ scope.digest();只有$ scope。$$ pahse才会消化。
答案 4 :(得分:0)
您可以使用$scope.$evalAsync()
方法,而不是像@betaorbust正确建议的那样,通过$scope.$apply()
值检查在外部使用$$phase
:
我最近有机会向Misko(角度作者)询问有关$$$ phase的问题,他说从不使用它; 这是摘要周期的内部实现,因此未来也不安全。
$scope.$evalAsync()
的好处是,它可以为您提供真正的所需,并通过摘要周期获取新数据,甚至比$ timeout可以更快:
到目前为止,我对deferred- $ digest-invocation的处理方法是将$ scope。$ apply()调用替换为$ timeout()服务(在延迟后隐式调用$ apply())。但是,昨天,我发现了$ scope。$ evalAsync()方法。两者都完成同一件事-将表达式评估推迟到以后的某个时间点。但是,$ scope。$ evalAsync()可能会在JavaScript事件循环的同一时刻执行。
用法非常简单:
$scope.$evalAsync(
function() {
// Call some method here OR
$scope.excutemyMethod();
// assign some value;
$scope.someVariable = "asd"
}
);
$evalAsync()
内部的方法被添加到异步队列中,以便可以通过内部触发$apply
在接下来的摘要周期中执行,这正是我们真正想要的。
它还包括$timeout
调用,以处理最罕见的罕见情况,以观察异步队列长度并等待异步队列中的任务被执行,以使您的功能尽快进入执行周期。请参阅Ben Nadel blog,它解释了这一事实。