AngularJS'de veri bağlama nasıl çalışır?


1956

Veri bağlama AngularJSçerçevede nasıl çalışır ?

Ben ilişkin teknik ayrıntıları bulamadı kendi sitesinde . Veriler görünümden modele yayıldığında nasıl çalıştığı az çok açıktır. Ancak AngularJS, model özellikleri değişikliklerini ayarlayıcılar ve alıcılar olmadan nasıl izler?

Bu işi yapabilecek JavaScript gözlemcileri olduğunu buldum . Ancak Internet Explorer 6 ve Internet Explorer 7'de desteklenmez . Peki AngularJS, örneğin aşağıdakileri değiştirdiğimi ve bu değişikliği bir görünüme yansıttığımı nasıl biliyor?

myobject.myproperty="new value";

10
Açısal 1.0.0rc1'den bu yana, moderinizin hemen güncellenmesi için ng-model-instant ( docs-next.angularjs.org/api/… ) belirtmeniz gerektiğini unutmayın. Aksi takdirde bulanıklık olayında güncellenir.
Sotomajor

8
Marcello'nun bağlantısı görünüşte koptu, işte burada: github.com/mhevery/angular.js/blob/master/docs/content/guide/…
riffraff

6
@orian, bu bağlantı kötü. (sanırım) güncellendi aynı - docs.angularjs.org/guide/databinding
Kevin Meredith

11
Hala bu soruyu okuyanlar için, Angular 2.0'ın web bileşenleri ile çalışmak ve aşağıdaki cevaplardaki birçok sorunu ele almak için Angular 1.x'ten beri veri tabanı oluşturma konusundaki yönlerini büyük ölçüde değiştirdiğini lütfen unutmayın.
ağustos

Yanıtlar:


2744

AngularJS değeri hatırlar ve önceki bir değerle karşılaştırır. Bu temel bir kirli kontroldür. Değerde bir değişiklik varsa, change olayını başlatır.

$apply()Eğer, bir angularjs dünyaya olmayan bir angularjs dünyadan aramaları geçişi sırasında diyoruz yöntem $digest(). Bir sindirim sadece düz eski kirli kontrol. Tüm tarayıcılarda çalışır ve tamamen tahmin edilebilir.

Kirli denetleme (AngularJS) ile değişiklik dinleyicilerini ( KnockoutJS ve Backbone.js ) karşılaştırmak için: Kirli denetim basit ve hatta verimsiz görünse de (bunu daha sonra ele alacağım), her zaman anlamsal olarak doğru olduğu ortaya çıkıyor, değişiklik dinleyicilerinde çok garip köşe vakaları vardır ve daha anlamsal olarak doğru hale getirmek için bağımlılık izleme gibi şeylere ihtiyaç duyarlar. KnockoutJS bağımlılık izleme, AngularJS'nin sahip olmadığı bir sorun için akıllı bir özelliktir.

Değişiklik dinleyicileriyle ilgili sorunlar:

  • Sözdizimi iğrenç, çünkü tarayıcılar yerel olarak desteklemiyor. Evet, proxy'ler var, ancak her durumda anlamsal olarak doğru değiller ve elbette eski tarayıcılarda proxy yok. Sonuç olarak, kirli kontrol POJO yapmanıza izin verirken, KnockoutJS ve Backbone.js sizi sınıflarından miras almaya ve verilerinize erişimciler aracılığıyla erişmeye zorlar.
  • Birleşmeyi değiştirin. Bir dizi öğeniz olduğunu varsayalım. Bir diziye öğe eklemek istediğinizi varsayalım, eklemek için döngü oluşturduğunuzda, her eklediğinizde, değişiklik yaptığınızda etkinlikleri düzenler ve kullanıcı arayüzünü oluşturur. Bu performans için çok kötü. İstediğiniz şey, kullanıcı arayüzünü yalnızca bir kez, sonunda güncellemektir. Değişiklik olayları çok hassas.
  • Değişiklik dinleyicisi, bir sorun gidericiye hemen ateş eder, bu da bir sorundur, çünkü değişiklik dinleyicisi verileri daha fazla değiştirebilir, bu da daha fazla değişiklik olayını tetikler. Bu, yığınızda aynı anda birkaç değişiklik etkinliğiniz olabileceğinden kötüdür. Herhangi bir nedenle senkronize edilmesi gereken iki diziniz olduğunu varsayalım. Yalnızca birini veya diğerini ekleyebilirsiniz, ancak her eklediğinizde, şimdi dünyanın tutarsız bir görüşüne sahip olan bir değişiklik olayı başlatırsınız. Bu, her geri arama özel olarak yürütüldüğünden ve tamamlandığından JavaScript'in önlediği iş parçacığı kilitlemesine çok benzer bir sorundur. Ayarlayıcılar, amaçlanmayan ve açık olmayan, iş parçacığı sorununu yeniden yaratan çok geniş kapsamlı sonuçlara sahip olabileceğinden, bu olayları bozar. Yapmak istediğiniz şeyin dinleyicinin çalışmasını geciktirmek ve garantilemek olduğu ortaya çıkıyor,

Performans ne olacak?

Kirli kontrol yetersiz olduğundan, yavaş olduğumuz anlaşılıyor. Burası sadece teorik argümanlara sahip olmak yerine gerçek sayılara bakmamız gereken yerdir, ama önce bazı kısıtlamaları tanımlayalım.

İnsanlar:

  • Yavaş - 50 ms'den daha hızlı olan herhangi bir şey insanlar tarafından algılanamaz ve bu nedenle "anlık" olarak kabul edilebilir.

  • Sınırlı - Tek bir sayfada bir insana yaklaşık 2000'den fazla bilgi gösteremezsiniz. Bundan daha fazla bir şey gerçekten kötü kullanıcı arayüzü ve insanlar bunu yine de işleyemiyor.

Asıl soru şudur: Bir tarayıcıda 50 ms'de kaç karşılaştırma yapabilirsiniz? Bu, birçok faktörün devreye girmesiyle cevaplanması zor bir soru, ancak burada bir test örneği: http://jsperf.com/angularjs-digest/6 , 10.000 izleyici yaratıyor. Modern bir tarayıcıda bu, 6 ms'den biraz daha az sürer. On Internet Explorer 8 40 ms sürer. Gördüğünüz gibi, bu günlerde yavaş tarayıcılarda bile bir sorun değil. Bir uyarı var: Karşılaştırmaların zaman sınırına uyması basit olmalı ... Ne yazık ki AngularJS'ye yavaş bir karşılaştırma eklemek çok kolay, bu nedenle ne yaptığınızı bilmediğinizde yavaş uygulamalar oluşturmak çok kolay yapıyorlar. Ancak, yavaş karşılaştırmaların hangileri olduğunu gösteren bir enstrümantasyon modülü sağlayarak bir cevap almayı umuyoruz.

Video oyunlarının ve GPU'ların, özellikle tutarlı olduğu için kirli kontrol yaklaşımını kullandıkları ortaya çıkıyor. Monitörün yenileme hızını (tipik olarak 50-60 Hz veya her 16,6-20 ms'de) aştıkları sürece, bunun üzerindeki herhangi bir performans bir israftır, bu nedenle FPS'yi yükseltmekten daha fazla malzeme çekmekten daha iyidir.


32
@Mark - evet, KO'da, son değişiklik olayından sonra harekete geçmeden önce 500 milisaniye beklemek için .extend ({throttle: 500}) ekleyin.
Daniel Earwicker

158
Bu yanıtın tamamı, "50 fps aldıkları sürece, bunun üzerindeki herhangi bir performans bir israftır, çünkü insan gözü bunu takdir edemez, bu nedenle fps'yi yükseltmekten daha fazla şey çizmekten daha iyidir." Bu ifade, uygulamanıza bağlı olarak tamamen yanlıştır. Göz kesinlikle 50 fps'den fazla değer kazanabilir ve VR şovuyla ilgili çeşitli sorunlar (John Carmack veya Michael Abrash'in en sonlarından herhangi birini okuyun, özellikle ikincinin GDC 2013 VR konuşması), 50 fps aslında çok yavaş. Bunun dışında cevabınız harika. Yanlış bilginin yayılmasını istemiyorum.
Nate Bundy

10
Biziz @DavidRivers sadece utorrent 1 ms'de = 0.000001s gibi iS
ÞORGEIR

33
"Kirli kontrol, nakavt olmayan bir sorun için akıllı bir özelliktir" gibi tersine kolayca söylenebilir. ES6 gözlenebilirler kullanıyor ve açısal kirli kontrolden kurtuluyor. Gerçek dünya bu cevabı yakaladı ve yanlış olduğunu gösterdi.
konik

17
"50 ms'den daha hızlı olan herhangi bir şey insanlar tarafından algılanamaz" doğru değildir. Testlerde müşterilerimizin 50ms güncelleme gecikmesini (20fps) ve 16.6ms güncelleme gecikmesini (60fps) kolayca ayırt edebildiklerini bulduk. Önceki hızda çalışan sahneler, insanlar kare hızını bilinçli bir şekilde kaydettirmediklerinde bile genel olarak "nasıl hissettim" derecelendirmelerini sürekli olarak daha da kötüleştirir.
Crashworks

323

Misko, veri bağlarının nasıl çalıştığına dair mükemmel bir açıklama yaptı, ancak veri bağlama ile ilgili performans sorunu hakkındaki görüşümü eklemek istiyorum.

Misko'nun belirttiği gibi, yaklaşık 2000 ciltleme sorunları görmeye başladığınız yerdir, ancak yine de bir sayfada 2000'den fazla bilgi olmamalıdır. Bu doğru olabilir, ancak her veri bağlama kullanıcı tarafından görülemez. İki yönlü ciltleme ile herhangi bir widget veya veri ızgarası oluşturmaya başladığınızda , kötü bir UX'a sahip olmadan 2000 bağlantıyı kolayca vurabilirsiniz.

Örneğin, kullanılabilir seçenekleri filtrelemek için metin yazabileceğiniz bir birleşik giriş kutusu düşünün. Bu tür bir kontrol ~ 150 maddeye sahip olabilir ve yine de son derece kullanılabilir. Ekstra bir özelliği varsa (örneğin, şu anda seçili olan seçenekte belirli bir sınıf), seçenek başına 3-5 bağlama almaya başlarsınız. Bu widget'lardan üçünü bir sayfaya koyun (örneğin, bir ülke seçmek için diğeri adı geçen ülkede bir şehir seçmek için, üçüncüsü de bir otel seçmek için) ve zaten 1000 ile 2000 arasında bir yerdesiniz.

Veya kurumsal bir web uygulamasında bir veri ızgarası düşünün. Her sayfada 10-20 sütun olabilen sayfa başına 50 satır mantıksız değildir. Bunu ng tekrarları ile oluşturursanız ve / veya bazı bağlamalar kullanan bazı hücrelerde bilgi sahibi olursanız, yalnızca bu ızgara ile 2000 bağlamaya yaklaşıyor olabilirsiniz.

AngularJS ile çalışırken bunun çok büyük bir sorun olduğunu düşünüyorum ve şimdiye kadar bulabildiğim tek çözüm, ngOnce, izleyicileri ve benzer hileleri silmek veya inşa etmek yerine iki yönlü ciltleme kullanmadan widget'lar oluşturmaktır. jQuery ve DOM manipülasyonu ile DOM'u oluşturan yönergeler. Bunun Angular'ı ilk etapta kullanma amacını yendiğini hissediyorum.

Bununla başa çıkmanın diğer yolları hakkında öneriler duymak isterim, ama sonra belki kendi sorumu yazmalıyım. Bunu bir yorum yapmak istedim, ama bunun için çok uzun olduğu ortaya çıktı ...

TL; DR
Veri bağlama karmaşık sayfalarda performans sorunlarına neden olabilir.


26
Evet, ikinci olarak. Bizim app birincil sorumluluğu farklı varlıklar arasındaki bağlantıları görüntülemek için. Belirli bir sayfada 10 bölüm bulunabilir. Her bölümün bir tablosu vardır. Her tablonun 2-5 daktilo filtresi vardır. Her tablonun her birinde 10 satır bulunan 2-5 sütun vardır. Çok hızlı bir şekilde mükemmel sorunlarla karşılaşıyoruz ve "benzer numaralar" seçenekleriyle devam ediyoruz.
Scott Silvi

10
Angular'ın sadece veri bağlama ile ilgili olmadığını ve bazı uygulamaların bu özelliği diğerlerinin belirttiği nedenlerle kullanmak istemeyeceğini söylemek adil mi? Bence DI ve modülerlik yaklaşımının kendisi çok değerlidir; sihirli otomatik bağlama güzel ancak mevcut her uygulamada performans değiş tokuşları var. Angular'ın yolu, CRUD web uygulamalarının çoğunluğu için tartışmasız daha üstündür ve insanlar sadece bir duvara aşırıya kaçmaya çalışarak vuruyorlar. Alternatif bir olay dinleme yönteminin desteklenmesi iyi olurdu, ancak belki de bu temelde tek bir çerçeve için çok karmaşıktır?
Jason Boyd

8
Açısal şimdi bu soruna yardımcı olmak için tek yönlü ve bir kez veri bağlama vardır. Dahası, artık tekrarlayıcı kaynağınız için dizinler içeriyor, bu da tüm içerik için dom'u yeniden oluşturmadan listeyi değiştirmenizi sağlar.
Mayıs'ta

6
@MW. Dürüst olmak gerekirse, bir kez bağlamanın özde olduğunu düşündüm. Ama öyle değil. Bu sadece kendi direktiflerinizi yazarken yapabileceğiniz bir şeydir. Ancak bunun için bir ux modu var: github.com/pasvaz/bindonce
Gaute Løken

9
Bunu okuyan herkes için gelecekten gelen bir not: Bir kerelik ciltleme şimdi Angular v1.3'teki
Nobita

158

$scopeNesneyi kirli kontrol ederek

Açısal array, $scopenesnelerdeki basit izleyicileri korur . Eğer herhangi birini incelerseniz $scopebunun bir arrayçağrı içeriyor olduğunu göreceksiniz $$watchers.

Her izleyici, objectdiğer şeylerin yanı sıra

  1. İzleyicinin izlediği bir ifade. Bu sadece bir attributeisim veya daha karmaşık bir şey olabilir .
  2. İfadenin bilinen son değeri. Bu, ifadenin geçerli hesaplanan değerine göre kontrol edilebilir. Değerler farklıysa, gözlemci işlevi tetikler ve $scopekirli olarak işaretler .
  3. İzleyici kirliyse yürütülecek bir işlev.

İzleyiciler nasıl tanımlanır?

AngularJS'de bir izleyici tanımlamanın birçok farklı yolu vardır.

  • Açıkça can $watchbir attributeüstünde $scope.

    $scope.$watch('person.username', validateUnique);
  • {{}}Şablonunuza bir enterpolasyon yerleştirebilirsiniz (geçerli olarak sizin için bir izleyici oluşturulur $scope).

    <p>username: {{person.username}}</p>
  • ng-modelİzleyiciyi sizin için tanımlamak gibi bir yönerge isteyebilirsiniz .

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

$digestDöngüsü son değerlerinde karşı gözlemcileri denetler

AngularJS ile normal kanallar (ng-model, ng-tekrar, vb.) Üzerinden etkileşime girdiğimizde, direktif tarafından bir özet döngüsü tetiklenir.

Bir sindirim döngüsü, tüm çocuklarının ve derinliğinin ilk geçişidir$scope . Her biri için $scope object, onun üzerinde tekrarlıyoruz $$watchers arrayve tüm ifadeleri değerlendiriyoruz. Yeni ifade değeri bilinen son değerden farklıysa, gözlemcinin işlevi çağrılır. Bu işlev, DOM'un bir bölümünü yeniden derleyebilir, üzerinde bir değeri yeniden hesaplayabilir , yapmanız gereken herhangi $scopebir AJAX requestşeyi tetikleyebilir .

Her kapsam geçer ve her saat ifadesi değerlendirilir ve son değerle karşılaştırılır.

Bir izleyici tetiklenirse, $scopekirli

Bir izleyici tetiklenirse, uygulama bir şeyin değiştiğini bilir ve $scopekirli olarak işaretlenir.

İzleme işlevleri $scopebir üst öğedeki veya üst öğedeki diğer özellikleri değiştirebilir $scope. Bir $watcherişlev tetiklenmişse, diğer işlevlerimizin $scopehala temiz olduğunu garanti edemeyiz ve bu nedenle tüm sindirim döngüsünü tekrar yürütürüz.

Bunun nedeni AngularJS'nin iki yönlü bağlanması olduğundan, veriler $scopeağaca geri aktarılabilir . Daha $scopeönce sindirilmiş olan daha yüksek bir değeri değiştirebiliriz . Belki de bir değer değiştiririz $rootScope.

Eğer $digestkirli, biz tüm yürütmek $digesttekrar döngüsünü

$digestSindirim döngüsü temiz olana kadar (tüm $watchifadeler önceki döngüdeki değerlerle aynı olana kadar ) veya özüm sınırına ulaşana kadar döngü boyunca sürekli döngü yaparız. Varsayılan olarak, bu sınır 10 olarak ayarlanmıştır.

Özet sınırına ulaşırsak AngularJS konsolda bir hata oluşturur:

10 $digest() iterations reached. Aborting!

Özet, makinede zor, ancak geliştiricide kolay

Gördüğünüz gibi, bir AngularJS uygulamasında her şey değiştiğinde AngularJS, $scopenasıl yanıt verileceğini görmek için hiyerarşideki her izleyiciyi kontrol edecektir . Bir geliştirici için bu büyük bir üretkenlik nimetidir, şimdi neredeyse hiçbir kablolama kodu yazmanız gerekmediğinden, AngularJS sadece bir değerin değişip değişmediğini fark edecek ve uygulamanın geri kalanını değişiklikle tutarlı hale getirecektir.

Bu makinenin perspektifinden çılgınca verimsiz ve çok fazla izleyici yaratırsak uygulamamızı yavaşlatacaktır. Misko, uygulamanız eski tarayıcılarda yavaş hissetmeden önce yaklaşık 4000 gözlemciden alıntı yaptı.

Örneğin ng-repeatbüyük bir sınırın üzerindeyseniz bu sınıra ulaşmak kolaydır JSON array. İzleyici oluşturmadan bir şablonu derlemek için tek seferlik ciltleme gibi özellikleri kullanarak buna karşı hafifletebilirsiniz.

Çok fazla izleyici oluşturmaktan kaçınma

Kullanıcınız uygulamanızla her etkileşim kurduğunda, uygulamanızdaki her izleyici en az bir kez değerlendirilir. Bir AngularJS uygulamasını optimize etmenin büyük bir kısmı, $scopeağacınızdaki izleyici sayısını azaltmaktır . Bunu yapmanın kolay bir yolu tek seferlik ciltlemedir .

Nadiren değişecek verileriniz varsa, :: sözdizimini kullanarak yalnızca bir kez bağlayabilirsiniz, şöyle:

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

veya

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

Bağlama yalnızca içerdiği şablon oluşturulduğunda ve içine veri yüklendiğinde tetiklenir $scope.

Bu, ng-repeatbirçok öğeye sahip olduğunuzda özellikle önemlidir .

<div ng-repeat="person in people track by username">
  {{::person.username}}
</div>

Teşekkürler @ user2864740 - Misko'nun cevabının en üstte olması doğru olsa da. Çerçeveyi herkesten daha iyi biliyor ve Stack Overflow ile etkileşime
girmesi

4
Bu cevabın en üstte olması gerektiğine katılmıyorum; bir şeyi bilmek ve belirli bir soru için alakalı / ayrıntılı bir cevap yazmak arasında bir fark vardır. Övgü almanın daha iyi yolları var. Her neyse ..
user2864740

1
Böyle doğru olduğundan şüphe etmiyorum, ama soruları cevaplar ve cevapları cevaplar :)
user2864740

3
Kirli çekin nasıl davrandığını ve gerçekte neyi değerlendirdiğini kapsayan güzel bir cevap, Misko'nun cevabında bir şey çok açık değildi.
strider

3
Mükemmel ve ayrıntılı cevap. @superluminary, böyle bir cevap için teşekkürler. Dahası, bu cevabı okuduktan sonra, izlenen bir ifade olarak idempotent olmayan bir ifade eklemememiz gerektiği noktasına geliyorum.
Mangu Singh Rajpurohit

81

Bu benim temel anlayışım. Yanlış olabilir!

  1. Öğeler, bir fonksiyonun (izlenecek olanı döndürerek) $watchyönteme geçirilerek izlenir .
  2. İzlenen öğelerde yapılan değişiklikler, $applyyöntem tarafından sarılmış bir kod bloğu içinde yapılmalıdır .
  3. Yöntemin sonunda , saatlerin her birinden geçen ve son kez çalıştırıldığından beri değişip değişmediğini kontrol $applyeden $digestyöntem çağrılır $digest.
  4. Herhangi bir değişiklik bulunursa, tüm değişiklikler dengelenene kadar özet tekrar çağrılır.

Normal geliştirmede, HTML'deki veri bağlama sözdizimi AngularJS derleyicisine sizin için saatler oluşturmasını söyler ve denetleyici yöntemleri $applyzaten içeride çalıştırılır . Yani uygulama geliştirici için her şey şeffaftır.


4
uygulama yöntemi ne zaman tetiklenir?
numan salati

3
@EliseuMonar Özet döngüsü bir olayın veya $ camera () çağrısının bir sonucu olarak çalışır, bir zamanlayıcıya göre periyodik olarak çağrılmaz. bkz. AngularJS'in $ watch işlevi nasıl çalışır? ve AngularJS'de ciltleme ve sindirim nasıl çalışır?
adl

1
@remi, AngularJS'nin son sürümü hakkında endişelenmiyorum. Zaten proxy veya Object.observe kullanıyorlar mı? Değilse, hala kirli kontrol çağındalar, bu da model niteliklerinin değişip değişmediğini görmek için zamanlanmış bir döngü oluşturur.
Eliseu Monar dos Santos

1
i özet on günlerin bir max çalışacağı okudum sitepoint.com/understanding-angulars-apply-digest
user137717

62

Bunu bir süre merak ettim. Ayarlayıcılar olmadan AngularJSbildirim $scopenesnede nasıl değişiklik yapar ? Onları yoklıyor mu?

Aslında yaptığı şey: Modeli değiştirdiğiniz herhangi bir "normal" yer zaten bağırsaklardan çağrıldı AngularJS, bu yüzden $applykodunuz çalıştıktan sonra otomatik olarak sizi çağırır . Denetleyicinizin ng-clickbazı öğelere bağlı bir yöntemi olduğunu varsayalım . Bu AngularJSyöntemi sizin için arayarak kablolar $apply, uygun bir yerde bir yapmak için şansı var . Aynı şekilde, sağ görünümlerde ifadeleri, kişiler tarafından yürütülür AngularJSöyle böylece $apply.

Belgeler , dışında$apply kod için manuel olarak arama yapmaktan bahsettiğinde, çalıştırıldığında çağrı yığınında kendisinden kaynaklanmayan koddan bahseder .AngularJSAngularJS


32

Resimlerle Açıklama:

Veri Bağlama için bir eşleme gerekir

Kapsamdaki başvuru, tam olarak şablondaki başvuru değildir. İki nesneyi veri bağladığınızda, ilkini dinleyen ve diğerini değiştiren üçüncü bir nesneye ihtiyacınız vardır.

resim açıklamasını buraya girin

Burada, değiştirdiğinizde <input>ona dokunup veri REF3 . Ve klasik veri bağlama mekanizması, veri ref4'ü değiştirecektir . Peki diğer {{data}}ifadeler nasıl hareket edecek?

Etkinlikler $ digest ()

resim açıklamasını buraya girin

Açısal , her bağlamanın bir oldValueve daha newValuefazlasını korur . Ve her Açısal olaydan sonra , ünlü $digest()döngü bir şeyin değişip değişmediğini görmek için İzleme Listesini kontrol edecektir. Bunlar Açısal olaylar vardır ng-click, ng-change, $httptamamlanmış ... $digest()sürece herhangi olarak bir şekilde döngü oldValuedeğişmesidir newValue.

Önceki resimde, data-ref1 ve data-ref2'nin değiştiğini göreceksiniz.

Sonuçlar

Biraz Yumurta ve Tavuk gibi. Kimin başladığını asla bilemezsiniz, ama umarım çoğu zaman beklendiği gibi çalışır.

Diğer bir nokta ise, bellek ve CPU üzerindeki basit bir bağlamanın derinlikteki etkisini kolayca anlayabilmenizdir. Umarım Masaüstü bilgisayarlar bunu başaracak kadar şişman. Cep telefonları o kadar güçlü değil.


22

Açıkçası Scope, kendisine bağlı Nesnelerde herhangi bir değişiklik olup olmadığının periyodik kontrolü yoktur . Kapsama bağlı olan tüm nesneler izlenmez. Scope bir $$ gözlemciyi prototip olarak korur . ScopeSadece bu dolaşır $$watcherszaman $digestdenir.

Açısal, $$ watchers'a bunların her biri için bir watcher ekler

  1. {{expression}} - Şablonlarınızda (ve ifadenin bulunduğu başka herhangi bir yerde) veya ng-modelini tanımladığımızda.
  2. $ scope. $ watch ('expression / function') - JavaScript'inizde açısalın izlenmesi için bir kapsam nesnesi ekleyebiliriz.

$ watch işlevi üç parametre alır:

  1. Birincisi, sadece nesneyi döndüren bir gözlemci fonksiyonudur ya da sadece bir ifade ekleyebiliriz.

  2. İkincisi, nesnede bir değişiklik olduğunda çağrılacak bir dinleyici işlevidir. DOM değişiklikleri gibi her şey bu işlevde uygulanacaktır.

  3. Üçüncüsü, bir boole alan isteğe bağlı bir parametredir. Doğru, açısal derin nesneyi izliyorsa ve yanlış Açısal ise nesneyi izleyen bir referans yapar. $ Watch'un Kaba Uygulaması şöyle görünür

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

Açısal'da Özet Döngü adı verilen ilginç bir şey var. $ Digest döngüsü, $ scope. $ Digest () çağrısı sonucunda başlar. Bir tıklama işlevinde ng kapsamı yönergesini kullanarak bir $ kapsam modelini değiştirdiğinizi varsayın. Bu durumda AngularJS, $ digest () öğesini çağırarak otomatik olarak $ digest döngüsünü tetikler. Ng-click'e ek olarak, modelleri değiştirmenize izin veren birkaç başka yerleşik yönerge / hizmet de vardır (örn. Ng-model, $ timeout, vb.) ve otomatik olarak $ digest döngüsünü tetikler. $ Digest'in kabaca uygulanması şu şekildedir.

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

Bir kapsam modelini güncellemek için JavaScript'in setTimeout () işlevini kullanırsak, Angular'ın neyi değiştirebileceğinizi bilmesinin bir yolu yoktur. Bu durumda, $ digest döngüsünü tetikleyen $ application () öğesini manuel olarak aramak bizim sorumluluğumuzdur. Benzer şekilde, bir DOM olay dinleyicisi ayarlayan ve işleyici işlevi içindeki bazı modelleri değiştiren bir yönerge varsa, değişikliklerin etkili olmasını sağlamak için $ application () öğesini çağırmanız gerekir. $ Apply'ın büyük fikri, Angular'ın farkında olmayan bazı kodları yürütebileceğimiz, bu kodun kapsamdaki şeyleri değiştirebileceğidir. Bu kodu $ uygula'ya sarırsak, $ digest () çağrısı ile ilgilenir. $ Apply () öğesinin kaba uygulaması.

Scope.prototype.$apply = function(expr) {
       try {
         return this.$eval(expr); //Evaluating code in the context of Scope
       } finally {
         this.$digest();
       }
};

15

AngularJS, veri bağlama mekanizmasını üç güçlü işlev yardımıyla işler: $ watch () , $ digest () ve $ Apply () . AngularJS çoğu zaman $ scope. $ Watch () ve $ scope. $ Digest () öğesini çağırır, ancak bazı durumlarda yeni işlevlerle güncellemek için bu işlevleri manuel olarak çağırmanız gerekebilir.

$ watch () : -

Bu işlev $ kapsamındaki bir değişkendeki değişiklikleri gözlemlemek için kullanılır. Üç parametreyi kabul eder: dinleyici ve eşitlik nesnesinin isteğe bağlı parametreler olduğu ifade, dinleyici ve eşitlik nesnesi.

$ digest () -

Bu işlev $ scope nesnesindeki tüm saatler ve child $ scope nesneleri
(varsa) üzerinden yinelenir . $ Digest () saatler üzerinde tekrarladığında, ifadenin değerinin değişip değişmediğini kontrol eder. Değer değiştiyse, AngularJS dinleyiciyi yeni değer ve eski değerle çağırır. AngularJS gerekli olduğunu düşündüğünde $ digest () işlevi çağrılır. Örneğin, bir düğmeyi tıklattıktan sonra veya bir AJAX çağrısından sonra. AngularJS'nin $ digest () işlevini sizin için çağırmadığı bazı durumlar olabilir. Bu durumda, bunu kendiniz çağırmalısınız.

$ uygulamak () -

Açısal, yalnızca AngularJS bağlamındaki model değişikliklerini otomatik olarak günceller. Açısal bağlamın dışındaki herhangi bir modelde (tarayıcı DOM olayları, setTimeout, XHR veya üçüncü taraf kitaplıkları gibi) değişiklik yaptığınızda, değişiklikleri açısal olarak $ uygula () öğesini çağırarak bilgilendirmeniz gerekir. $ Apply () işlev çağrısı bittiğinde, AngularJS $ digest () öğesini dahili olarak çağırır, böylece tüm veri bağlamaları güncellenir.


7

Bir kişinin veri modelini bir forma bağlamak zorunda kaldım, yaptığım, verilerin formla doğrudan eşleştirilmesiydi.

Örneğin, model şöyle bir şey içeriyorsa:

$scope.model.people.name

Formun kontrol girişi:

<input type="text" name="namePeople" model="model.people.name">

Bu şekilde, nesne denetleyicisinin değerini değiştirirseniz, bu görünümde otomatik olarak yansıtılır.

Modeli geçirdiğim bir örnek, sunucu verilerinden güncellendiği bir örnek, yazılı yüklere dayalı bir posta kodu ve posta kodu istediğinde, bu görünümle ilişkili kolonilerin ve şehirlerin bir listesini ve varsayılan olarak kullanıcı ile ilk değeri ayarladığınız zamandır. Ve bu çok iyi çalıştım, ne oluyor, angularJSbazen modelin yenilenmesi birkaç saniye sürüyor, bunu yapmak için verileri görüntülerken bir döndürücü koyabilirsiniz.


14
Bu cevabı 5 kez okudum ve hala burada ne anlama geldiğini anlamıyorum.
sbedulin

1
Cevap benim için bulmaca gibi görünüyor
Aman

6
  1. Tek yönlü veri bağlama, veri modelinden bir değer alındığı ve bir HTML öğesine yerleştirildiği bir yaklaşımdır. Modeli görünümden güncellemenin bir yolu yoktur. Klasik şablon sistemlerinde kullanılır. Bu sistemler verileri yalnızca bir yönde bağlar.

  2. Açısal uygulamalarda veri bağlama, model ve görünüm bileşenleri arasında verilerin otomatik senkronizasyonudur.

Veri bağlama, modeli uygulamanızda gerçeğin tek kaynağı olarak değerlendirmenizi sağlar. Görünüm, modelin her zaman bir projeksiyonudur. Model değiştirilirse, görünüm değişikliği yansıtır veya tam tersi de geçerlidir.


5

Aşağıda bir girdi alanı kullanarak AngularJS ile veri bağlama örneği verilmiştir. Daha sonra açıklayacağım

HTML Kodu

<div ng-app="myApp" ng-controller="myCtrl" class="formInput">
     <input type="text" ng-model="watchInput" Placeholder="type something"/>
     <p>{{watchInput}}</p> 
</div>

Açısal JS Kodu

myApp = angular.module ("myApp", []);
myApp.controller("myCtrl", ["$scope", function($scope){
  //Your Controller code goes here
}]);

Yukarıdaki örnekte de görebileceğiniz gibi, AngularJSng-model , HTML öğelerinde, özellikle inputalanlarda neler olduğunu dinlemek ve izlemek için kullanır . Bir şey olduğunda, bir şey yap. Bizim durumumuzda, ng-modelbıyık notasyonunu kullanarak görüşümüze bağlanıyor {{}}. Giriş alanına yazılanlar anında ekranda görüntülenir. Ve bu veri bağlamanın güzelliği, AngularJS'yi en basit haliyle kullanıyor.

Bu yardımcı olur umarım.

Codepen'de çalışan bir örneği burada görebilirsiniz


5

AngularJs İki yönlü veri bağlama özelliğini destekler .
Verilere erişebileceğiniz anlamına gelir Görünüm -> Denetleyici ve Denetleyici -> Görünüm

Örn.

1)

// If $scope have some value in Controller. 
$scope.name = "Peter";

// HTML
<div> {{ name }} </div>

O / P

Peter

Verileri aşağıdaki gibi bağlayabilirsiniz ng-model: -
2)

<input ng-model="name" />

<div> {{ name }} </div>

Yukarıdaki örnekte kullanıcı ne verirse girsin, <div>etiketinde görünür olacak .

Girdiyi html'den denetleyiciye bağlamak istiyorsanız: -
3)

<form name="myForm" ng-submit="registration()">
   <label> Name </lbel>
   <input ng-model="name" />
</form>

Burada namedenetleyicideki girişi kullanmak istiyorsanız ,

$scope.name = {};

$scope.registration = function() {
   console.log("You will get the name here ", $scope.name);
};

ng-modelgörüşümüzü bağlar ve ifadede oluşturur {{ }}.
ng-modelgörünümde kullanıcıya gösterilen ve kullanıcının etkileşimde bulunduğu verilerdir.
Bu nedenle AngularJ'lerde veri bağlamak kolaydır.


4

Angular.js, görünümde oluşturduğumuz her model için bir izleyici oluşturur. Bir model değiştirildiğinde, modele bir "ng-dirty" sınıfı eklenir, böylece gözlemci "ng-dirty" sınıfına sahip tüm modelleri gözlemler ve değerlerini kontrolörde günceller veya tersi de geçerlidir.


3

bağlanma verileri:

Veri bağlama nedir?

Kullanıcı görünümdeki verileri her değiştirdiğinde, kapsam modelinde ve viceversa'da bu değişikliğin bir güncellemesi gerçekleşir.

Bu nasıl mümkün olaiblir?

Kısa cevap: Sindirim döngüsü yardımı ile.

Açıklama: Açısal js, modelde bir değişiklik olması durumunda dinleyici işlevini başlatan kapsam modelinde izleyiciyi ayarlar.

$scope.$watch('modelVar' , function(newValue,oldValue){

// Yeni değerli Dom güncelleme kodu

});

Peki, gözlemci işlevi ne zaman ve nasıl çağrılır?

İzleyici fonksiyonu özet döngüsünün bir parçası olarak adlandırılır.

Sindirim döngüsü, sindirim döngüsünü tetiklemenizi sağlayan ng-model, ng-bind, $ timeout, ng-click ve diğerleri gibi direktiflerde / servislerde yerleşik açısal j'lerin bir parçası olarak otomatik olarak tetiklenir.

Özet döngüsü fonksiyonu:

$scope.$digest() -> digest cycle against the current scope.
$scope.$apply() -> digest cycle against the parent scope 

yani$rootScope.$apply()

Not: $ Apply (), $ rootScope'a eşittir. $ Digest (), kirli denetimin doğrudan kökten veya üstten veya üst kapsamdan açısal js uygulamasındaki tüm alt $ kapsamlarına kadar başladığı anlamına gelir.

Yukarıdaki özellikler, sadece uygulamanızın komut dosyası etiketinde başvurulan angularjs framework komut dosyasını kullandığınız anlamına gelen açısal js uygulaması olduğundan emin olarak bahsedilen sürümler için tarayıcılarda çalışır.

Teşekkür ederim.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.