Kaip veikia duomenų rinkimas AngularJS?

Kaip veikia duomenų rinkimas AngularJS ?

Neradau savo svetainės techninių detalių. Tai daugiau ar mažiau aišku, kaip tai veikia, kai duomenys perduodami pagal modelį. Bet kaip „AngularJS“ stebi modelio savybių pokyčius be nustatymų ir getterių?

Radau, kad „ JavaScript“ stebėtojai gali atlikti šį darbą. Tačiau jie nepalaikomi „ Internet Explorer 6“ ir „ Internet Explorer 7“ . Taigi, kaip „AngularJS“ žino, kad pasikeitiau, pavyzdžiui, taip ir atspindėjau šį pateikimo pakeitimą?

 myobject.myproperty="new value"; 
1690 m
13 марта '12 в 13:16 2012-03-13 13:16 Pashec yra nustatytas kovo 13, 12, 13:16 2012-03-13 13:16
@ 13 atsakymų

AngularJS prisimena vertę ir palygina ją su ankstesne verte. Tai yra pagrindinis purvinas patikrinimas. Jei yra vertės pasikeitimas, tai sukelia pokyčio įvykį.

$apply() metodas, kurį skambinate, kai einate iš pasaulio be kampų į AngularJS pasaulį, skambina $digest() . Virškinimas yra tik paprastas purvinas patikrinimas. Jis veikia visose naršyklėse ir yra visiškai nuspėjamas.

Priešingai nei purvinas čekis (AngularJS) ir klausytojų keitimas ( KnockoutJS ir Backbone.js ): nors purvo tikrinimas gali atrodyti paprasta ir netgi neveiksminga (aš apie tai kalbėsiu vėliau), paaiškėja, kad jis visą laiką yra semantiškai teisingas, o Pakeisti klausytojus turi daug keistų kampų atvejų ir reikalingi tokie dalykai, kaip priklausomybės stebėjimas, kad jis taptų semantiškai teisingas. Priklausomybės stebėjimas „KnockoutJS“ yra protingas bruožas problemai, kurios neturi „AngularJS“.

Problemos su pakeitimo klausytojais:

  • Sintaksė yra žiauri, nes naršyklės iš pradžių nepalaiko. Taip, yra įgaliotinis, bet visais atvejais jie nėra semantiškai teisingi, ir, žinoma, senose naršyklėse nėra proxy serverių. Esmė yra ta, kad purvinas nuskaitymas leidžia atlikti POJO , o „KnockoutJS“ ir „Backbone.js“ priverčia jus paveldėti savo klases ir pasiekti duomenis per priedus.
  • Pakeiskite sutapimą. Tarkime, jūs turite daugybę elementų. Tarkime, kad norite pridėti elementų į masyvą, nes pridedate kilpą, kiekvieną kartą pridedant, paleidžiate įvykius su pakeitimais, rodančiais vartotojo sąsają. Tai labai bloga našumui. Norite atnaujinti sąsają tik vieną kartą, pabaigoje. Pakeisti įvykius yra per maži.
  • Keičiantys klausytojai nedelsiant įsijungia į seterį, o tai yra problema, nes pakeitimo klausytojas gali papildomai keisti duomenis, kurie sukelia daugiau įvykių pokyčių. Tai blogai, nes jūsų sklype jums gali įvykti keli pakeitimai. Tarkime, jūs turite dvi matricas, kurias reikia sinchronizuoti dėl bet kokios priežasties. Galite pridėti tik vieną ar kitą, bet kiekvieną kartą, kai pridėsite, įvykdysite pakeitimo įvykį, kuris dabar turi nenuoseklią pasaulio vaizdą. Tai labai panašus dalykas, skirtas blokuoti temas, kurias „JavaScript“ vengia, nes kiekvienas atgalinis ryšys yra vykdomas tik ir nutraukiamas. Keičiant įvykius tai pažeidžiami, nes steigėjai gali turėti toli siekiančių pasekmių, kurios nėra skirtos ir nėra akivaizdžios, o tai vėl sukelia srauto problemą. Pasirodo, kad norite atidėti klausytojo vykdymą ir užtikrinti, kad tuo pačiu metu veiktų tik vienas klausytojas, todėl bet kuris kodas gali laisvai keisti duomenis, ir jis žino, kad, kai tai daro, nėra jokio kito kodo.

Kaip apie našumą?

Taigi gali atrodyti, kad mes lėtai, nes purvinas patikrinimas yra neveiksmingas. Čia mes turime pažvelgti į realius skaičius, o ne tik teorinius argumentus, bet pirmiausia nustatome kai kuriuos apribojimus.

Žmonės:

  • Lėtas - nieko greičiau nei 50 ms žmonėms nepastebima ir todėl gali būti laikoma „akimirksniu“.

  • Limited. Viename puslapyje asmeniui negalima rodyti daugiau nei 2000 informacijos. Kažkas daugiau nei ši tikrai bloga vartotojo sąsaja ir žmonės vis dar negali su ja elgtis.

Taigi, tikrasis klausimas yra toks: kiek palyginimų galite padaryti naršyklėje 50 ms? Tai yra sudėtingas klausimas, į kurį reikia atsakyti, nes daugelis veiksnių pasirodo, bet čia yra bandomasis atvejis: http://jsperf.com/angularjs-digest/6 , kuris sukuria 10 000 stebėtojų. Šiuolaikinėje naršyklėje užtrunka tik 6 µs. „Internet Explorer 8“ trunka apie 40 μs. Kaip matote, šiandien tai nėra problema net lėtose naršyklėse. Yra įspėjimas: palyginimas turėtų būti paprastas pagal laiko apribojimus ... Deja, pernelyg lengva pridėti lėtą palyginimą „AngularJS“, todėl lengva kurti lėtas programas, kai nežinote, ką darote. Tačiau tikimės gauti atsakymą pateikdami instrumentų modulį, kuris parodys jums, kas yra lėtas palyginimas.

Pasirodo, kad vaizdo žaidimai ir grafikos procesoriai naudojasi nešvariu būdu, ypač todėl, kad jis yra suderintas. Tol, kol jie viršys monitoriaus atnaujinimo dažnį (paprastai 50-60 Hz arba kas 16,6–20 ms), bet koks našumas, palyginti su šiuo, yra atliekos, taigi geriau geriau nei gauti FPS.

2577
14 марта '12 в 2:47 2012-03-14 02:47 atsakymą Misko Hevery pateikė kovo 14 d. 12 val. 2:47 2012-03-14 02:47

„Misko“ jau puikiai apibūdino, kaip veikia duomenų rišikliai, tačiau norėčiau pridėti savo idėją apie našumo problemą, susijusią su duomenimis.

Kaip sakė Mishko, apie 2000 surišimų yra ta vieta, kur pradėsite matyti problemas, tačiau bet kuriuo atveju puslapyje neturėtų būti daugiau nei 2000 informacijos. Tai gali būti tiesa, bet ne visi duomenys yra susieti su vartotoju. Kai pradėsite kurti valdiklį arba dviejų krypčių duomenų tinklelį, galite lengvai nukentėti 2000 susiejimų be blogų „ux“.

Pavyzdžiui, apsvarstykite kombinuotą kopiją, kurioje galite įvesti tekstą, kad galėtumėte filtruoti turimus parametrus. Tokia kontrolė gali turėti ~ 150 elementų ir gali būti labai naudinga. Jei ji turi papildomą funkciją (pvz., Tam tikrą klasę šiuo metu pasirinktame parametre), kiekvienam parametrams gaunate 3-5 susiejimus. Įdėkite tris iš šių įtaisų puslapyje (pvz., Pasirinkite šalį, o kitą - norėdami pasirinkti miestą nurodytoje šalyje, o trečiąjį - pasirinkti viešbutį), o jūs esate kažkur tarp 1000 ir 2000 m.

Arba peržiūrėkite duomenų tinklą įmonės žiniatinklio programoje. 50 eilučių per puslapį nėra nepagrįsti, kiekviename iš jų gali būti 10-20 stulpelių. Jei sukursite šią funkciją su ng pakartojimais ir (arba) gausite informacijos kai kuriose ląstelėse, kuriose naudojami tam tikri įrišimai, galite pasiekti beveik 2000 susiejimų tik su šiuo tinklu.

border=0

Manau, kad tai yra didžiulė problema dirbant su „AngularJS“, ir vienintelis sprendimas, kurį galėjau rasti iki šiol, yra sukurti valdiklius nenaudojant dvipusio įpareigojimo, o ne naudojant „ngOnce“, išregistruojant stebėtojus ir pan. kad sukurtų DOM su manipuliacija jQuery ir DOM. Manau, kad tai prieštarauja „Angular“ tikslo naudojimui.

Norėčiau išgirsti kitų būdų, kaip tai spręsti, pasiūlymus, tačiau galbūt turėčiau parašyti savo klausimą. Aš norėjau tai įtraukti į komentarus, tačiau paaiškėjo, kad tai buvo per ilgai ...

Tl; DR
Duomenų įpareigojimas gali sukelti sudėtingų puslapių veikimo problemas.

295
Atsakymą pateikia MW. Rugpjūčio 22 d 2013-08-22 16:28 '13, 16:28, 2013-08-22 16:28

Nešvarus $ apimties objekto nuskaitymas

Kampinis palaiko paprastą stebėtojų masyvą $ apimtų objektuose. Jei patikrinsite bet kurią „$“ sritį, pamatysite, kad jame yra masyvas, vadinamas „$ $ watchers“.

Kiekvienas stebėtojas yra objektas, kuriame, be kita ko, yra

  • Stebėtojo pastebima išraiška. Tai gali būti tik atributo pavadinimas arba kažkas sudėtingesnis.
  • Paskutinė žinoma išraiška. Tai galima patikrinti pagal dabartinę apskaičiuotą išraišką. Jei vertės yra skirtingos, stebėtojas skambins funkcijai ir pažymės $ sritį kaip purviną.
  • Funkcija, kuri bus atliekama, jei stebėtojas yra purvinas.

Kaip nustatomi stebėtojai

Yra daug skirtingų būdų apibrėžti stebėtoją AngularJS.

  • Galite aiškiai matyti $ atributą „$“ apimtyje.

     $scope.$watch('person.username', validateUnique); 
  • Interpoliaciją {{}} galite įdėti į savo šabloną (jums bus sukurtas stebėtojas pagal dabartinę $ taikymo sritį).

     <p>username: {{person.username}}</p> 
  • Galite nurodyti direktyvą, pvz., Ng-modelį, kad nustatytumėte stebėtoją.

     <input ng-model="person.username" /> 

$ Digest ciklas tikrina visus stebėtojus už jų paskutinę vertę.

Kai mes sąveikaujame su kampais per įprastinius kanalus (ng-model, ng-pakartoti ir pan.), Konversijos ciklą inicijuos direktyva.

Virškinimo ciklas yra pirmojo $ apimties ir visų jos vaikų sankirtos gylis . Už kiekvieną $ apimties objektą mes kartojame per $ $ watchers masyvą ir įvertiname visas išraiškas. Jei nauja išraiškos vertė skiriasi nuo paskutinės žinomos vertės, vadinama stebėtojo funkcija. Ši funkcija gali perskaičiuoti DOM dalį, perskaičiuoti vertę $ aprėptyje, sukelti AJAX užklausą.

Kiekvienas regionas yra išlaikomas, ir kiekvienas laikrodis išreiškiamas ir patikrinamas pagal paskutinę vertę.

Jei stebėtojas užsidega, parametras $ ulatus yra purvinas

Jei stebėtojas veikia, programa žino, kad kažkas pasikeitė, o $ sritis pažymėta kaip nešvari.

„Watcher“ funkcijos gali keisti kitus atributus „$“ arba „$ ulatus“ kintamajame. Jei buvo iškviesta viena $ watcher funkcija, negalime garantuoti, kad mūsų kiti $ apimtys vis dar yra švarūs, todėl vėl atliekame visą apdorojimo ciklą.

Taip yra dėl to, kad 1 kampas turi dvipusį ryšį, todėl duomenys gali būti perkelti atgal į $ apimties medį. Mes galime pakeisti vertę iki didesnės $ apimties, kuri jau buvo suardyta. Galbūt mes pakeisime vertę į $ rootScope.

Jei $ digest yra purvinas, dar kartą vykdome $ digest ciklą.

Mes nuolatos kartojame per $ digest ciklą tol, kol bus aišku, kad apdorojimo ciklas yra aiškus (visos $ watch išraiškos turi tą pačią reikšmę kaip ir ankstesniame cikle), arba pasiekiame virškinimo ribą. Pagal numatytuosius nustatymus ši riba yra 10.

Jei pasiekiame kampinio virškinimo ribą, tai sukels klaidą konsolėje:

 10 $digest() iterations reached. Aborting! 

Kolekcija yra sudėtinga mašinoje, bet kūrėjui paprasta

Kaip matote, kiekvieną kartą, kai kažkas pasikeičia kampiniame taikyme, kampinis patikrina kiekvieną stebėtoją $ apimties hierarchijoje, kad pamatytų, kaip reaguoti. Programuotojui tai yra didžiulis našumo balas, nes dabar nereikia rašyti vielos kodo be kodo, kampinis tiesiog pastebės, jei pasikeitė vertė ir kad resto programa bus suderinama su pakeitimu.

Įrenginio požiūriu, nors tai yra labai neefektyvi ir sulėtins mūsų taikymą, jei sukursime per daug stebėtojų. „Misko“ nurodė apie 4 000 stebėtojų skaičių, kol jūsų paraiška jaučiama lėtai senose naršyklėse.

Ši riba yra lengvai pasiekiama, jei, pavyzdžiui, kartojate didelį JSON masyvą. Tai galite sušvelninti naudodami tokias funkcijas kaip vienkartinis įpareigojimas, kad sukurtumėte šabloną nesukuriant stebėtojų.

Kaip išvengti per daug stebėtojų

Kiekvieną kartą, kai naudotojas bendrauja su jūsų paraiška, kiekvienas jūsų paraiškos stebėtojas bus vertinamas bent kartą. Dauguma kampinio pritaikymo optimizavimo sumažina stebėtojų skaičių jūsų $ apimties medyje. Vienas paprastas būdas tai padaryti yra laiko nuoroda.

Jei turite duomenų, kurie retai keičiasi, galite ją susieti tik vieną kartą, naudodami sintaksę :: like this:

 <p>{{::person.username}}</p> 

arba

 <p ng-bind="::person.username"></p> 

Susiejimas bus pradėtas tik tada, kai pateikiamas turinys su šablonu ir duomenimis, įkeltais į $ taikymo sritį.

Tai ypač svarbu, jei turite daugybę elementų.

 <div ng-repeat="person in people track by username"> {{::person.username}} </div> 
120
02 июня '15 в 15:31 2015-06-02 15:31 atsakymas pateikiamas superluminalui birželio 02-15 d. 15:31 2015-06-02 15:31

Tai yra mano pagrindinis supratimas. Galbūt tai negerai!

  • Elementai yra peržiūrimi perduodant funkciją (kuri grąžina vaizdą, kurį reikia peržiūrėti) į $watch metodą.
  • Stebėtų elementų pakeitimai turėtų būti atliekami kodų bloke, suvyniotame naudojant $apply metodą.
  • $apply , naudojamas „ $digest metodas, kuris eina per kiekvieną laikrodį ir patikrina, ar jie pasikeitė nuo paskutinio „ $digest .
  • Jei randama bet kokių pakeitimų, iškirpimas vėl vadinamas, kol visi pakeitimai stabilizuosis.

Normaliomis raidėmis HTML duomenų įpareigojanti sintaksė nurodo „AngularJS“ kompiliatoriui sukurti laikrodį jums, o valdiklio metodai jau yra vykdomi viduje $apply . Todėl programos kūrėjas yra skaidrus.

73
14 марта '12 в 0:01 2012-03-14 00:01 atsakymą pateikė Pete BD kovo 14 d. 12 val. 0:01 2012-03-14 00:01

Jau kurį laiką aš apie tai galvojau. Kaip AngularJS ataskaita pasikeičia į $scope objektą be nustatymų? Ar jie juos interviu?

Tai, ką ji iš tikrųjų daro, yra tokia: bet kokia „normalioji“ vieta, kurią pakeitėte, jau yra skambinama iš „AngularJS“ žarnų, todėl automatiškai skambina „ $apply “ jums, kai paleisite kodą. Tarkime, kad jūsų valdiklis turi metodą, kuris prisijungia prie tam tikro elemento ng-click . Kadangi „AngularJS“ su jumis susieja skambutį į šį metodą, jis gali atlikti $apply taikymą tinkamoje vietoje. Panašiai ir išraiškose, kurios rodomos tiesiogiai nuomonėse, jas atlieka „AngularJS“, taigi jis $apply .

Kai dokumentuose teigiama, kad kodą reikia skambinti $apply rankiniu būdu už kodą ne AngularJS, jis kalba apie kodą, kuris, paleidus, nėra susijęs su „AngularJS“ skambučių kamino.

54
03 сент. atsakymas duotas jpsimons 03 sep . 2012-09-03 20:45 '12, 08:45 pm 2012-09-03 20:45

Paaiškinimas su nuotraukomis:

Duomenų susiejimas reikalauja žemėlapio

Nuoroda regione nėra šablono nuoroda. Kai susiejate duomenis su dviem objektais, jums reikia trečiojo, kuris klauso pirmojo ir keičia kitą.

2019

Akivaizdu, kad nėra periodinio patikrinimo Scope ar prie jo pridedamų objektų yra kokių nors pakeitimų. Nematomi visi prie regiono pritvirtinti objektai. Prototipo sritis palaiko „ $ watchers“ . Scope tik kartojasi per „ $$watchers kai vadinamas $digest .

Kampinis prideda stebėtoją prie „$ $“ stebėtojų kiekvienam iš jų.

  • {{expression}} - Jūsų šablonuose (ir kur nors kitur, kur yra išraiška) arba kai apibrėžiame ng-modelį.
  • $ taikymo sritis. $ watch („išraiška / funkcija“). Savo „javascript“ mes galime tiesiog pridėti vietinį objektą, kad galėtumėte peržiūrėti kampą.

$ Watch funkcija atlieka tris parametrus:

  • Pirmasis yra stebėtojo funkcija, kuri tiesiog grąžina objektą, arba mes galime tiesiog pridėti išraišką.

  • Antrasis yra klausytojo funkcija, kuri bus vadinama, kai objektas pasikeis. Ši funkcija įgyvendins visus tokius dalykus, kaip DOM pakeitimai.

  • Trečiasis yra neprivalomas parametras, kurio vertė yra loginė. Jei jos teisingas, kampinis atrodo giliai į objektą ir jei jo klaidingas kampas tiesiog atlieka nuorodą, kuri stebi objektą. Neteisingas „$ watch“ įgyvendinimas atrodo taip:

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

Kampiniame kampe yra įdomus dalykas, vadinamas Digest Cycle. „$ Digest“ ciklas prasideda, kai skambinate „$“ sritimi. $ Digest (). Tarkime, jūs pakeisite $ apimties modelį tvarkytojo funkcijoje naudodami ng-click direktyvą. Tokiu atveju „AngularJS“ automatiškai pradeda $ digest kilpą, vadindama $ digest (). Be ng-click, yra keletas kitų integruotų direktyvų / paslaugų, leidžiančių keisti modelius (pvz., Ng-modelį, $ timeout ir tt) ir automatiškai pradėti „$ digest“ ciklą. Apytikris $ digest įgyvendinimas yra toks.

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

Jei naudosime „ setTimeout“ () „ JavaScripts“ funkciją, kad atnaujintume taikymo sritį, kampinis neturi jokio būdo žinoti, ką galite keisti. Tokiu atveju jis yra atsakingas už „$ application“ () kreipimąsi rankiniu būdu, o tai sukelia „$ digest“ ciklą. Panašiai, jei turite direktyvą, nustatančią DOM įvykių klausytoją ir keičiant kai kuriuos tvarkytojo funkcijos modelius, turite skambinti „$ kohaldatakse“ (), kad užtikrintumėte, jog pakeitimai įsigalios. Didžioji „$ application“ idėja yra ta, kad mes galime atlikti tam tikrą kodą, kuris nežino apie kampinį, šis kodas vis tiek gali pakeisti lauką. Jei taikysime šį kodą $, jis pasirūpins, kad paskambintų $ digest (). Neteisingas $ taikymas ().

 Scope.prototype.$apply = function(expr) { try { return this.$eval(expr); //Evaluating code in the context of Scope } finally { this.$digest(); } }; 
16
ответ дан Sasank Sunkavalli 22 мая '16 в 21:18 2016-05-22 21:18

AngularJS обрабатывает механизм привязки данных с помощью трех мощных функций: $watch() , $digest() и $apply() . В большинстве случаев AngularJS будет вызывать $scope. $Watch() и $scope. $Digest(), но в некоторых случаях вам может потребоваться выполнить эти функции вручную, чтобы обновить новые значения.

$watch() : -