Πώς λειτουργεί η δέσμευση δεδομένων στο πλαίσιο AngularJS
;
Δεν έχω βρει τεχνικές λεπτομέρειες στον ιστότοπό τους. Είναι περισσότερο ή λιγότερο σαφές πώς λειτουργεί όταν τα δεδομένα διαδίδονται από την προβολή στο μοντέλο. Αλλά πώς παρακολουθεί το AngularJS τις αλλαγές των ιδιοτήτων του μοντέλου χωρίς setters και getters;
Βρήκα ότι υπάρχουν JavaScript watchers που μπορούν να κάνουν αυτή τη δουλειά. Αλλά δεν υποστηρίζονται από τον Internet Explorer 6 και τον Internet Explorer 7. Πώς λοιπόν το AngularJS γνωρίζει ότι άλλαξα για παράδειγμα το παρακάτω και αντανακλά αυτή την αλλαγή σε μια προβολή;
myobject.myproperty="new value";
Το AngularJS θυμάται την τιμή και τη συγκρίνει με μια προηγούμενη τιμή. Πρόκειται για βασικό έλεγχο βρωμιάς. Εάν υπάρχει αλλαγή στην τιμή, τότε πυροδοτεί το συμβάν αλλαγής.
Η μέθοδος $apply()
, την οποία καλείτε όταν μεταβαίνετε από έναν κόσμο που δεν είναι AngularJS σε έναν κόσμο AngularJS, καλεί την $digest()
. Ένα digest είναι ένας απλός παλιός βρώμικος έλεγχος. Λειτουργεί σε όλα τα προγράμματα περιήγησης και είναι απολύτως προβλέψιμη.
Για να αντιπαραβάλουμε το dirty-checking (AngularJS) έναντι των change listeners (KnockoutJS και Backbone.js): Ενώ το dirty-checking μπορεί να φαίνεται απλό, ακόμα και αναποτελεσματικό (θα αναφερθώ σε αυτό αργότερα), αποδεικνύεται ότι είναι σημασιολογικά σωστό όλη την ώρα, ενώ οι change listeners έχουν πολλές περίεργες γωνιακές περιπτώσεις και χρειάζονται πράγματα όπως η παρακολούθηση εξαρτήσεων για να είναι πιο σημασιολογικά σωστό. Η παρακολούθηση εξαρτήσεων του KnockoutJS είναι ένα έξυπνο χαρακτηριστικό για ένα πρόβλημα που δεν έχει το AngularJS.
Μπορεί λοιπόν να φαίνεται ότι είμαστε αργοί, αφού ο έλεγχος βρωμιάς είναι αναποτελεσματικός. Εδώ είναι που πρέπει να δούμε πραγματικούς αριθμούς και όχι να έχουμε μόνο θεωρητικά επιχειρήματα, αλλά πρώτα ας'ορίσουμε κάποιους περιορισμούς.
Οι άνθρωποι είναι:
Αργά - Οτιδήποτε είναι ταχύτερο από 50 ms είναι ανεπαίσθητο για τους ανθρώπους και συνεπώς μπορεί να θεωρηθεί "στιγμιαίο".
Περιορισμένα - Δεν μπορείτε πραγματικά να δείξετε περισσότερες από περίπου 2000 πληροφορίες σε έναν άνθρωπο σε μία μόνο σελίδα. Οτιδήποτε περισσότερο από αυτό είναι πραγματικά κακό UI, και οι άνθρωποι δεν μπορούν να το επεξεργαστούν αυτό ούτως ή άλλως.
Έτσι, το πραγματικό ερώτημα είναι το εξής: ms; πόσες συγκρίσεις μπορείτε να κάνετε σε ένα πρόγραμμα περιήγησης σε 50 ms; Αυτή είναι μια δύσκολη ερώτηση για να απαντηθεί, καθώς πολλοί παράγοντες παίζουν ρόλο, αλλά εδώ είναι μια περίπτωση δοκιμής: http://jsperf.com/angularjs-digest/6 που δημιουργεί 10.000 παρατηρητές. Σε ένα σύγχρονο πρόγραμμα περιήγησης αυτό διαρκεί λίγο λιγότερο από 6 ms. Στον Internet Explorer 8 χρειάζεται περίπου 40 ms. Όπως μπορείτε να δείτε, αυτό δεν αποτελεί πρόβλημα ακόμη και σε αργούς φυλλομετρητές στις μέρες μας. Υπάρχει μια προειδοποίηση: Οι συγκρίσεις πρέπει να είναι απλές για να χωρέσουν στο χρονικό όριο... Δυστυχώς είναι πάρα πολύ εύκολο να προσθέσετε μια αργή σύγκριση στο AngularJS, οπότε είναι εύκολο να δημιουργήσετε αργές εφαρμογές όταν δεν ξέρετε τι κάνετε. Ελπίζουμε όμως να έχουμε μια απάντηση παρέχοντας ένα instrumentation module, το οποίο θα σας δείχνει ποιες είναι οι αργές συγκρίσεις.
Αποδεικνύεται ότι τα βιντεοπαιχνίδια και οι GPUs χρησιμοποιούν την προσέγγιση dirty-checking, ειδικά επειδή είναι συνεπής. Εφόσον ξεπερνούν το ρυθμό ανανέωσης της οθόνης (συνήθως 50-60 Hz, ή κάθε 16,6-20 ms), οποιαδήποτε απόδοση πάνω από αυτό είναι σπατάλη, οπότε καλύτερα να σχεδιάζετε περισσότερα πράγματα, παρά να ανεβάζετε τα FPS υψηλότερα.
Αυτή είναι η βασική μου αντίληψη. Μπορεί κάλλιστα να είναι λάθος!
$watch
.$apply
.$apply
καλείται η μέθοδος $digest
η οποία πηγαίνει
μέσα από κάθε ένα από τα watches και ελέγχει αν έχουν αλλάξει από τότε που
την τελευταία φορά που εκτελέστηκε η $digest
.Στην κανονική ανάπτυξη, η σύνταξη δέσμευσης δεδομένων στην HTML λέει στον μεταγλωττιστή του AngularJS να δημιουργήσει τα watches για εσάς και οι μέθοδοι του ελεγκτή εκτελούνται ήδη μέσα στο $apply
. Έτσι, για τον προγραμματιστή της εφαρμογής είναι όλα διαφανή.
Το αναρωτήθηκα κι εγώ για λίγο. Χωρίς setters πώς παρατηρεί το AngularJS
τις αλλαγές στο αντικείμενο $scope
; Μήπως τις ρωτάει;
Αυτό που κάνει στην πραγματικότητα είναι το εξής: Οποιοδήποτε "κανονικό" μέρος που τροποποιείτε το μοντέλο έχει ήδη κληθεί από τα σπλάχνα του AngularJS
, οπότε καλεί αυτόματα το $apply
για εσάς μετά την εκτέλεση του κώδικά σας. Ας πούμε ότι ο ελεγκτής σας έχει μια μέθοδο που συνδέεται με το ng-click
σε κάποιο στοιχείο. Επειδή το AngularJS
καλωδιώνει την κλήση αυτής της μεθόδου μαζί για εσάς, έχει την ευκαιρία να κάνει ένα $apply
στο κατάλληλο σημείο. Ομοίως, για τις εκφράσεις που εμφανίζονται ακριβώς στις προβολές, αυτές εκτελούνται από το AngularJS
, ώστε να κάνει το $apply
.
Όταν η τεκμηρίωση μιλάει για το ότι πρέπει να καλέσετε χειροκίνητα το $apply
για κώδικα _εκτός του AngularJS
, μιλάει για κώδικα που, όταν εκτελείται, δεν προέρχεται από το ίδιο το AngularJS
στη στοίβα κλήσεων.