What means “Observer reaction functions should not

2020-04-09 21:20发布

问题:

Here's a simplified version of the code where I get an error that is logged even if the generated HTML looks good. What does this exception means ? Why do I get it ?

index.html :

<!DOCTYPE html>
<div ng-app main>
  <div ng-repeat="a in ctrl.listOfA">
    <strong>{{ a }}</strong>
    <div ng-repeat="b in ctrl.listOfB(a)">
      {{ b }}
    </div>
  </div>
</div>

<script type="application/dart" src="main.dart"></script>
<script src="packages/browser/dart.js"></script>

main.dart :

import 'package:angular/angular.dart';  /* 0.9.10 */

@NgController(selector: '[main]', publishAs: 'ctrl')
class MainController {
  final listOfA = new List.generate(2, (i) => 'a$i');
  listOfB(a) => new List.generate(2, (i) => 'b$i').map((e) => '$a-$e');
}

void main() {
  ngBootstrap(module: new Module()
    ..type(MainController)
  );
}

The logged error :

Observer reaction functions should not change model. 
These watch changes were detected: ctrl.listOfB(a): (a0-b0, a0-b1) <= (a0-b0, a0-b1); ctrl.listOfB(a): (a1-b0, a1-b1) <= (a1-b0, a1-b1)
These observe changes were detected: 

STACKTRACE:
#0      RootScope.flush.<anonymous closure> (package:angular/core/scope.dart:554:11)
#1      RootScope.flush (package:angular/core/scope.dart:560:9)
#2      RootScope.flush (package:angular/core/scope.dart:561:7)
#3      RootScope.flush (package:angular/core/scope.dart:561:7)
#4      apply (package:angular/core/scope.dart:262:18)
#5      _rootRun (dart:async/zone.dart:710)
#6      _rootRun (dart:async/zone.dart:711)
#7      _rootRun (dart:async/zone.dart:711)
#8      _ZoneDelegate.run (dart:async/zone.dart:440)
#9      NgZone._finishTurn (package:angular/core/zone.dart:96:21)
#10     NgZone._onRunBase (package:angular/core/zone.dart:61:43)
#11     _onRun (package:angular/core/zone.dart:66:15)
#12     _ZoneDelegate.run (dart:async/zone.dart:440)
#13     _CustomizedZone.run (dart:async/zone.dart:650)
#14     NgZone.run (package:angular/core/zone.dart:148:35)
#15     ngBootstrap (package:angular/bootstrap.dart:92:18)
#16     main (http://127.0.0.1:3030/xxxx/web/test/main.dart:13:14)

回答1:

Angular only supports pure functions in expressions. I guess this started with 0.9.10 because there already was a similar question recently where it stopped working after the update.

ctrl.listOfB(a)

should always return the same result for the same argument,

or even if the result is the same, the cause could be that ctrl.listOfB(a) always returns a new instance of the same result. Angular 0.9.10 doesn't like this either.

It repeatedly evaluates the expression and if it receives a new result each time it throws.

I think the solution is to cache the results and return from the cache if already available.