Angularjs 正在调试$apply
我正在使用AngularJS开发一个Chrome扩展(因此它在CSP模式下运行)。amServices.js包含一个处理Chrome本机消息的服务。因此,在js/core/am/amServices.js:268:20中,相关代码如下:Angularjs 正在调试$apply,angularjs,google-chrome-extension,Angularjs,Google Chrome Extension,我正在使用AngularJS开发一个Chrome扩展(因此它在CSP模式下运行)。amServices.js包含一个处理Chrome本机消息的服务。因此,在js/core/am/amServices.js:268:20中,相关代码如下: chrome.runtime.onMessage.addListener( function (message, sender, sendResponse) { $rootScope.$apply(function () { if (me
chrome.runtime.onMessage.addListener(
function (message, sender, sendResponse) {
$rootScope.$apply(function () {
if (message.type == 'login' && message.state == 'ok') {
//huge if/else if here for every kind of message
我的理解是,由于这里的所有代码都是异步调用的,并且可以在大多数应用程序视图中触发修改,$rootScope.$apply是必需的。然而,我有时会在控制台中以一种完全随机的方式获得这些信息:
Error: [$rootScope:inprog] http://errors.angularjs.org/1.2.13/$rootScope/inprog?p0=%24apply
at Error (native)
at chrome-extension://hbfchfkepmidgcdfcpnodlnmfjhekcom/lib/angular/angular.min.js:6:450
at n (chrome-extension://hbfchfkepmidgcdfcpnodlnmfjhekcom/lib/angular/angular.min.js:98:34)
at h.$apply (chrome-extension://hbfchfkepmidgcdfcpnodlnmfjhekcom/lib/angular/angular.min.js:104:195)
at chrome-extension://hbfchfkepmidgcdfcpnodlnmfjhekcom/js/core/am/amServices.js:268:20
at Function.target.(anonymous function) (extensions::SafeBuiltins:19:14)
at Event.dispatchToListener (extensions::event_bindings:394:22)
at Event.dispatch_ (extensions::event_bindings:378:27)
at Event.dispatch (extensions::event_bindings:400:17)
at messageListener (extensions::messaging:192:31)
不,让我感到不安的是,与这里所解释的不同:
在堆栈跟踪中,我没有看到两个$apply调用,因此我无法知道冲突来自何处。另外,我不能运行AngularJS Batarang调试工具,因为它不能在CSP模式下工作
我忽略了这些错误,没有任何明显的后果,但我不确定忽略它们是否真的安全。关于如何知道哪两个apply调用触发了冲突,您有什么想法吗?如果您的问题是为什么?您希望只有当您有多个
$apply()
正如@J.Wells在对您的问题的评论中提到的,可能是因为其他angular
指令触发了$scope.$apply
和chrome.runtime
的回调发生在angular内部处于$$阶段时
查看一下forng click
,angularjs内部使用相同的$scope.$apply
,可供开发人员使用
<> P> >仅考虑角度指令,如<代码> NG点击,<代码> NG更改使用$Actudio评估表达式。$Apple,启动<代码> $Apdio< <代码>阶段,以及指令如<代码> NG如果和<代码> NG隐藏< /代码>使用$范围。
错误的理论,因为正如@Wawy所建议的,javascript是单线程的,因此在摘要中无法执行回调(左键,以便注释有意义):
如果在单击登录按钮时出现这种情况,并带有ng click
指令,可能是因为chrome在ng click
的$digest
阶段完成之前绑定和响应过快,因此执行了onMessage
回调。要回答这个问题,我们需要看看$digest和$apply的实现:
$digest: function() {
//Simplified code
beginPhase('$digest');
/* $$phase = 'digest'
From now on any code that calls $apply will cause an exception.
*/
lastDirtyWatch = null;
do { // "while dirty" loop
dirty = false;
current = target;
//Running any $evalAsync your code might have called
while(asyncQueue.length) {
try {
asyncTask = asyncQueue.shift();
// If any $evalAsync expression calls $apply will cause an exception.
asyncTask.scope.$eval(asyncTask.expression);
} catch (e) {
clearPhase();
$exceptionHandler(e);
}
lastDirtyWatch = null;
}
traverseScopesLoop:
do { // "traverse the scopes" loop
if ((watchers = current.$$watchers)) {
// process our watches
// If any $watch expression calls $apply it will cause an exception.
...
}
} while ((current = next));
} while (dirty || asyncQueue.length);
}
$apply:
$apply: function(expr) {
try {
beginPhase('$apply');
//Any code inside expr that calls $apply or any function that does it will cause an exception.
return this.$eval(expr);
} catch (e) {
$exceptionHandler(e);
} finally {
clearPhase();
try {
$rootScope.$digest();
} catch (e) {
$exceptionHandler(e);
throw e;
}
}
},
在分析了这两种方法后,我们发现了3个可能导致异常的地方:
$evalAsync表达式、$watch表达式和$apply表达式。因此,这些表达式中直接或间接调用$apply的任何代码都将触发异常
值得一提的是,angular在内部也调用$apply,因此如果您在angular“领域”内,就不应该调用$apply。我要做的一件事是使用angular的非精简版本,并查看其内部状态。它可能会变得复杂,但我有一些这样的调试想法。错误是说已经有一个$digest/$apply正在进行中。这类事情发生在听众触发摘要而不是订阅摘要时。Angular只在$digest中工作,因此如果Angular应用程序中发生了某些事情,则$digest/$apply已在程序中。您很可能可以使用$watch和/或$broadcast/$emit完成您想要完成的任务。很难在不知道更多的情况下给出进一步的建议。另外-$apply calls$digest(以防我没有正确地澄清)。你们甚至读过你们评论的问题吗?我知道错误的意思,也知道为什么会发生。问题是为什么堆栈跟踪没有显示两个不同的apply调用。哦,伙计-很抱歉,我们回答了一个您返回并编辑的问题。为了回答你评论中的问题,这里有$apply$apply:function(expr){try{beginPhase('$apply');返回这个。$eval(expr);}catch(e){$exceptionHandler(e);}最后是{clearPhase();try{$rootScope.$digest();}catch(e){$exceptionHandler(e);throw e;}}}
这就是为什么,genius。一个$digest对于应用程序是全局的,而不是特定于一个指令。它也是一个同步操作(就我而言,javascript是单线程的),因此我认为在执行$digest中的代码时不可能发生回调。$rootScope。$digest对于应用程序来说是全局的,但每个$scope都有自己的$digest。