How does data binding work in AngularJS?

前端 未结 14 1512
情话喂你
情话喂你 2020-11-21 05:41

How does data binding work in the AngularJS framework?

I haven\'t found technical details on their site. It\'s more or less clear how it works when data

相关标签:
14条回答
  • 2020-11-21 06:15

    Explaining with Pictures :

    Data-Binding needs a mapping

    The reference in the scope is not exactly the reference in the template. When you data-bind two objects, you need a third one that listen to the first and modify the other.

    Here, when you modify the <input>, you touch the data-ref3. And the classic data-bind mecanism will change data-ref4. So how the other {{data}} expressions will move ?

    Events leads to $digest()

    Angular maintains a oldValue and newValue of every binding. And after every Angular event, the famous $digest() loop will check the WatchList to see if something changed. These Angular events are ng-click, ng-change, $http completed ... The $digest() will loop as long as any oldValue differs from the newValue.

    In the previous picture, it will notice that data-ref1 and data-ref2 has changed.

    Conclusions

    It's a little like the Egg and Chicken. You never know who starts, but hopefully it works most of the time as expected.

    The other point is that you can understand easily the impact deep of a simple binding on the memory and the CPU. Hopefully Desktops are fat enough to handle this. Mobile phones are not that strong.

    0 讨论(0)
  • 2020-11-21 06:17

    Obviously there is no periodic checking of Scope whether there is any change in the Objects attached to it. Not all the objects attached to scope are watched . Scope prototypically maintains a $$watchers . Scope only iterates through this $$watchers when $digest is called .

    Angular adds a watcher to the $$watchers for each of these

    1. {{expression}} — In your templates (and anywhere else where there’s an expression) or when we define ng-model.
    2. $scope.$watch(‘expression/function’) — In your JavaScript we can just attach a scope object for angular to watch.

    $watch function takes in three parameters:

    1. First one is a watcher function which just returns the object or we can just add an expression.

    2. Second one is a listener function which will be called when there is a change in the object. All the things like DOM changes will be implemented in this function.

    3. The third being an optional parameter which takes in a boolean . If its true , angular deep watches the object & if its false Angular just does a reference watching on the object. Rough Implementation of $watch looks like this

    Scope.prototype.$watch = function(watchFn, listenerFn) {
       var watcher = {
           watchFn: watchFn,
           listenerFn: listenerFn || function() { },
           last: initWatchVal  // initWatchVal is typically undefined
       };
       this.$$watchers.push(watcher); // pushing the Watcher Object to Watchers  
    };
    

    There is an interesting thing in Angular called Digest Cycle. The $digest cycle starts as a result of a call to $scope.$digest(). Assume that you change a $scope model in a handler function through the ng-click directive. In that case AngularJS automatically triggers a $digest cycle by calling $digest().In addition to ng-click, there are several other built-in directives/services that let you change models (e.g. ng-model, $timeout, etc) and automatically trigger a $digest cycle. The rough implementation of $digest looks like this.

    Scope.prototype.$digest = function() {
          var dirty;
          do {
              dirty = this.$$digestOnce();
          } while (dirty);
    }
    Scope.prototype.$$digestOnce = function() {
       var self = this;
       var newValue, oldValue, dirty;
       _.forEach(this.$$watchers, function(watcher) {
              newValue = watcher.watchFn(self);
              oldValue = watcher.last;   // It just remembers the last value for dirty checking
              if (newValue !== oldValue) { //Dirty checking of References 
       // For Deep checking the object , code of Value     
       // based checking of Object should be implemented here
                 watcher.last = newValue;
                 watcher.listenerFn(newValue,
                      (oldValue === initWatchVal ? newValue : oldValue),
                       self);
              dirty = true;
              }
         });
       return dirty;
     };
    

    If we use JavaScript’s setTimeout() function to update a scope model, Angular has no way of knowing what you might change. In this case it’s our responsibility to call $apply() manually, which triggers a $digest cycle. Similarly, if you have a directive that sets up a DOM event listener and changes some models inside the handler function, you need to call $apply() to ensure the changes take effect. The big idea of $apply is that we can execute some code that isn't aware of Angular, that code may still change things on the scope. If we wrap that code in $apply , it will take care of calling $digest(). Rough implementation of $apply().

    Scope.prototype.$apply = function(expr) {
           try {
             return this.$eval(expr); //Evaluating code in the context of Scope
           } finally {
             this.$digest();
           }
    };
    
    0 讨论(0)
提交回复
热议问题