为什么我的 RXJS 下一个函数在$digest周期结束之前被调用,我该如何等待?



我有以下内容(在咖啡脚本中(

beforeEach "We should see the list changed event", (done) ->
constructorSubscription = importList.onListChanged().subscribe ->
# Expects
constructorSubscription.unsubscribe()
done()
doSomething()    
$rootScope.$apply()
it "Actual Test", (done) ->
importList.onListChanged().subscribe ->
# Expect conditions
done()
doSomethingElse()
$rootScope.$apply()

当这个测试运行时,它会进入$rootScope.应用和肚子痛

Error: [$rootScope:inprog] $digest already in progress http://errors.angularjs.org/1.6.4/$rootScope/inprog?p0=%24digest

这是因为摘要循环在完全完成运行之前调用主题的下一个方法。这使得$digest循环即使在调用 done 后也能运行。我可以通过将设置超时添加到完成来解决此问题...

setTimeout -> done()

只要摘要的时间不超过超时,它就可以工作,但这真的很麻烦。

是否有我可以关闭的事件来告诉我摘要何时完成?

附加信息

其他信息

正在测试的代码是 RXJS 主题,所以 doSomething 正在调用这样的东西......

@subject = new window.Rx.Subject()
...
onListChanged: => 
@subject.filter (message)=> # filter logic
...
doSomething: => 
@subject.next someValue
doSomethingElse: => 
@subject.next otherValue

如果我删除$apply则会出现超时错误

我也试过这个,但没有用

$timeout -> $rootScope.$apply()
$timeout.flush()

但这并没有帮助

更新

我根据答案尝试了这个,但它没有让我去任何地方

beforeEach "We should see the list changed event", (done) ->
constructorSubscription = importList.onListChanged().subscribe ->
# Expects
constructorSubscription.unsubscribe()
done()
$rootScope.$apply ->
doSomething() 
it "Actual Test", (done) ->
importList.onListChanged().subscribe ->
# Expect conditions
done()
$rootScope.$apply ->
doSomethingElse()

但它仍然说摘要周期正在运行

我也试过

beforeEach "We should see the list changed event", (done) ->
doSomething() 
$rootScope.$apply -> 
constructorSubscription = importList.onListChanged().subscribe ->
# Expects
constructorSubscription.unsubscribe()
done()
it "Actual Test", (done) ->        
doSomethingElse()
$rootScope.$apply ->
importList.onListChanged().subscribe ->
# Expect conditions
done()

这也不起作用,并且失败并出现相同的摘要正在进行错误

接下来我试了这个...

$rootScope.$apply -> done();

我再次看到相同的结果。

对于那些没有广泛使用CS的人

$rootScope.$apply ->
doSomethingElse()

编译为

$rootScope.$apply(function() {
return doSomethingElse();
});

$rootScope.$apply (->
doSomethingElse())

编译为

$rootScope.$apply((function() {
return doSomethingElse();
}));

所以它们是相同的

我注意到,当我第一次调用应用程序时,开始阶段被调用,但从不清除阶段。现在试图弄清楚为什么。

闪电版本:Angular 不会检查每个摘要上的每个值。只有当更改发生在 $apply(( 内部时,它才知道发生了什么变化。大多数情况下,这是隐藏的,因为它发生在使用标准角度指令/控制器的幕后,并且像往常一样绑定数据。完成后$apply将发生摘要。由于这些更改可以触发正在监视的其他内容,因此摘要将在每个周期运行多次。您看到的错误是因为您正在调用$apply在摘要周期已在进行时调用$digest。

如果更改是从外部来源进行的,即来自第三方的回调,则 angular 不知道它。您是正确的,您需要使用$apply,但是您应该向它传递一个可以在适当时间执行的函数。

我不知道咖啡脚本语法,但我认为这个 javascript 示例应该显示修复程序。

importList.onchange = function(){//callback for onchange
$scope.$apply(function(){ //use $apply an pass in function
constructorSubscription.unsubscribe();
done();
doSomething() ;
});
};

编辑:您为实现上述内容所做的咖啡脚本更改中存在错误。

特别是,这个

$rootScope.$apply ->
doSomethingElse()

应该是

$rootScope.$apply (->
doSomethingElse())

EDIt 我在这里错了,特定的语法是错误的

这是一个完整的工作示例 plunker

请注意,setInterval 在 angular 之外,因此它模拟了上面的示例。与此示例相比,如果您打开控制台,您可以看到它正确更改=ing值但不使用$apply。

最新更新