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

时间:2017-08-04 15:01:43

标签: angularjs coffeescript jasmine

我有以下(在Coffeescript中)

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.apply和腹部疼痛

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

这是因为摘要循环在完全运行之前调用了Subject的下一个方法。即使在调用done之后,这也会使$ digest循环继续运行。我可以通过添加setTimeout来完成这个...

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();
 }));

所以它们是相同的

我注意到,当我第一次打电话时,会调用beginPhase但从不清除阶段。试着找出原因。

1 个答案:

答案 0 :(得分:-1)

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

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

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

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

编辑:您为实现上述目标所做的coffeescript更改存在错误。

特别是,这个

$rootScope.$apply ->
    doSomethingElse()

应该是

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

EDIt我错了具体的语法错误

Here's a full working example plunker

请注意,setInterval超出了角度,因此它模拟了上面的示例。与This Example相比,如果你打开你的控制台,你可以看到它正确改变了值但不使用$ apply。