Angular 17 – @defer Deferrable Views
Merhaba,
Bu içeriğimizde Angular 17 ile component lazy loading davranışına karşın yeni bir yol olarak gelmiş olan @defer syntax’ı ile birlikte Deferrable Views özelliğini inceliyor olacağız.
@defer Nedir? Nasıl Bir İşleve Sahiptir?
@defer syntax’ı component’lere lazy loading davranışını uygulamanın yeni bir yolunu sağlayan özelliktir. İşlevsel olarak, bir koşula karşın lazy loading ile yüklenecek bir template bloğu tanımlanmasına olanak tanımaktadır. Bu blok içerisinde bulunan tüm component, pipe, directive ve library’ler lazy loading ile yüklenecektir.
Mevcut lazy loading davranışı Router mekanizmasına bağlıyken,
@deferile gelecek olan davranış selector üzerinden kullanılan component’ler ve kapsadıkları içerikleri için geçerlidir.
Misal olarak aşağıdaki çalışmayı ele alırsak eğer;
@Component({
selector: 'app-child2',
standalone: true,
imports: [CommonModule],
template: `Child2 Component`
})
export class Child2Component {
}
@Component({
selector: 'app-child1',
standalone: true,
imports: [CommonModule, Child2Component, ExamplePipe],
template: `Child1 Component
<br>
<app-child2></app-child2>
`
})
export class Child1Component {
}
@Component({
selector: 'app-home',
standalone: true,
imports: [CommonModule, Child1Component, ExampleDirective],
template: `Home Component
<br>
<app-child1></app-child1>
`
})
export class HomeComponent {
}
Görüldüğü üzere ‘Child2Component’ ‘Child1Component’te, ‘Child1Component’ ise ‘HomeComponent’te kullanılmaktadır. Ayrıca bu component’lere dikkat ederseniz ‘ExamplePipe’ ve ‘ExampleDirective’ yapıları da eşlik etmektedir. Ve nihai olarak ‘HomeComponent’in de ‘AppComponent’te aşağıdaki gibi kullanıldığını varsayalım.
@Component({
selector: 'app-root',
standalone: true,
imports: [CommonModule, RouterOutlet, HomeComponent],
template: `
<button>Change State</button>
@if(state){
<app-home></app-home>
}
`
})
export class AppComponent {
state: boolean = false;
ngOnInit() {
const button = document.getElementsByTagName("button");
fromEvent(button, "click").subscribe(() => {
this.state = !this.state;
})
}
}
Yukarıdaki kullanıma göz atarsanız eğer ‘HomeComponent’ sayfanın ilk yüklendiği anda gözükmemekte ve state değişkeninin değerine göre bu durum opsiyonel bir şekilde devam etmektedir. Şimdi -madem gözükmeyecekti o zaman bu component’i lazy loading ile yükleyeydik- dediğinizi duyar gibiyim. Ki makbul olanda budur. İşte bu durumda @defer özelliği ile ilgili component’i ve bu component’in kullandığı tüm alt component, pipe ve directive’leri kullanıcının gerçekten ihtiyacı olduğu durumda rahatlıkla yükleyebilirsiniz.
Şöyle ki;
<button>Change State</button>
@defer(when state){
<app-home></app-home>
}
İşte bu kadar 🙂
Görüldüğü üzere @defer kontrolü ile ilgili component(ve alt component’ler ile birlikte pipe ve directive’ler) koşul sağlandığında yüklenecektir ve böylece performanslı bir çalışma sergilenmiş olacaktır.
Şimdi @defer syntax’ının başka bir ilginç özelliğine odaklanalım. Ertelenmiş blok(deferred block) yüklenene kadar placeholder’ın görüntülenmesini…
@placeholder, @loading ve @error
@defer ile yükleme koşulu karşılanana kadar farklı bir görüntüde bulunmak istiyorsanız eğer @placeholder‘ı kullanabilirsiniz. Daha sonra yükleme koşulu karşılandığı taktirde component yüklenene kadar @loading‘den istifade edebilir ve yükleme sürecinde bir hatayla karşılaşılırsa eğer @error bloğunda gerekli önlemleri alabilirsiniz.
@defer(when state){
<app-home></app-home>
}
@placeholder {
...***...
}
@loading {
<marquee>Loading...</marquee>
}
@error {
Error
}
Burada unutulmaması gereken,
@deferiçeriği lazy loading’le yüklerken;@placeholder,@loadingve@erroreagerly loading ile yükleme gerçekleştirmektedir.
Ayrıca kimi durumlarda @defer bloğunun yüklenmesi oldukça hızlı olabileceğinden dolayı @loading bloğunun çok hızlı görüntülenip gizlenmesi ve bu durumdan kaynaklı bir titreşim etkisi riski söz konusu olabilmektedir. İşte bu duruma önlem amaçlı yüklemenin kaç milisaniye sonra görüntüleneceğini belirtmek için @loading bloğunda after seçeneğini kullanabilirsiniz.
@defer(when state){
<app-home></app-home>
}
@placeholder {
...***...
}
@loading(after 150ms;) {
<marquee>Loading...</marquee>
}
after, @defer içeriğinin yüklenmesi belirtilen zamansal değerden daha az sürdüğü taktirde @loading bloğunu hiçbir zaman görüntülemeyecektir. Böylece olası titreşim etkisi ortadan kaldırılmış olacaktır.
Ayrıca minimum seçeneği ile de yükleme için minimum süreyi belirleyebilirsiniz. Yani, @defer içeriğinin yüklenmesi minimum değerinden daha hızlıysa o taktirde @loading içeriği bu süre zarfında görüntülenecektir.
@defer(when state){
<app-home></app-home>
}
@placeholder {
...***...
}
@loading(minimum 150ms;) {
<marquee>Loading...</marquee>
}
Tabi isterseniz tüm bu seçenekleri aşağıdaki gibi kümülatif bir şekilde de kullanabilirsiniz;
@defer(when state){
<app-home></app-home>
}
@placeholder {
...***...
}
@loading(after 50ms;minimum 500ms;) {
<marquee>Loading...</marquee>
}
minimum seçeneği ayrıca @placeholder için de kullanılabilmektedir. Bu hiçbir koşul olmaksızın yüklemenin hemen gerçekleştiği durumlarda, olası titreşim etkisini önlemek için yararlı olabilir.
@placeholder(minimum 500ms) {
...***...
}
@defer Koşulları
Angular 17’de @defer özelliği ile birçok mantıkta koşullu davranış sergilenebilmektedir. Şimdi gelin bunları tek tek inceleyelim;
- Koşulsuz/
on idle
Hiçbir koşulun olmadığı durumdur.@defer{ <app-home></app-home> }ya da
@defer(on idle){ <app-home></app-home> }şeklinde ifade edilir.
- Boolean Koşulu/
when
Template’te yüklenecek bloğu basit bir boolean türden değere bağlayan koşuldur.@defer(when state){ <app-home></app-home> }@deferseçeneğininwhenkoşulu built-in gelen*ngIfdirektifinin davranışına benzetilebilir. İkisinin arasındaki radikal fark,*ngIfile yapılan kontrolde boolean değer false olduğu taktirde ilgili template görselden kaldırılırken,@defer‘ınwhenkoşulunda ise kaldırılmayacaktır. Sade ve sadece koşul gerçekleştiği taktirde ilgili blok yüklenecek şekilde işlevsellik gösterecektir. on immediate
on immediatekoşulu ile ilgili bloğun yüklenmesi hemen tetiklenebilmektedir.@defer(on immediate){ <app-home></app-home> }on timer
İlgili bloğun belirli bir süre sonra yüklenmesini tetikler.@defer(on timer(10s)){ <app-home></app-home> } @placeholder { ...***... }on hover

on hoverkoşulu ile kullanıcının template reference variable ile belirtilen html nesnesinin üzerine geldiğinde@deferiçeriğinin yüklenmesi tetiklenmektedir.<div #trigger> Hover me </div> @defer(on hover(trigger)){ <app-home></app-home> } @placeholder { ...***... }on interaction
on hover‘a benzer şekildeon interactionile de kullanıcının belirtilen html nesnesiyle click ya da keydown event’leriyle etkileşime girdiği taktirde@deferiçeriğinin yüklenmesi tetiklenmektedir.<div #trigger> Click me </div> @defer(on interaction(trigger)){ <app-home></app-home> } @placeholder { ...***... }on viewport
Belirtilen html öğesi görünür hale geldiği anda@deferbloğunun yüklemesini tetikler.<div #hi> Hi </div> @defer(on viewport(hi)){ <app-home></app-home> } @placeholder { ...***... }
Tüm bu koşulları kümülatif olarak kullanmak istiyorsanız eğer aşağıdaki gibi ,(virgül) ile çoklu bir kullanım sergileyebilirsiniz.
<div #trigger>
Hover me
</div>
@defer(on hover(trigger), timer(10s)){
<app-home></app-home>
}
@placeholder {
...***...
}
Buradaki çalışmaya göz atarsanız, @defer içeriği ya on hover(trigger) koşuluyla ilgili html öğesinin üzerine fareyle gelince yüklenecek ya da timer(10s) koşuluyla da 10 saniyeye kadar kendiliğinden yüklenecektir.
Prefetching
@defer özelliğinin prefetch özelliği ile bir component’in yüklenme maliyetini önceden karşılayarak, yukarıdaki satırlarda gördüğümüz herhangi bir koşulla görüntüleme işlemini gerçekleştirebiliriz. Misal olarak aşağıdaki gibi prefetch on idle komutu ile içeriği önceden yükleyebilir ve on interaction(trigger) komutu ile de ilgili html öğesine tıklanınca gösterebilirsiniz.
<div #trigger>
Hover me
</div>
@defer(on interaction(trigger); prefetch on idle){
<app-home></app-home>
}
@placeholder {
...***...
}
Nihai olarak;
Böylece Angular çalışmalarımıza oldukça pratik ve etkili bir nitelik kazandıracak olan @defer syntax’ını tam teferruatlı incelemiş bulunuyoruz. Nacizane olarak kanaatim odur ki; son zamanlardaki gelen yeniliklerden anlaşılan(Signals, Control Flow Syntax ve mevzu bahis @defer vs.), Angular ekibinin, bu mimarinin yarının SPA teknolojilerindeki sancaktarlığını garanti altına alma niyetinde ve ciddiyetindeler olduğudur. O yüzden Angular’la umutlu bir şekilde yola devam 🙂
İlgilenenlerin faydalanması dileğiyle…
Sonraki yazılarımda görüşmek üzere…
İyi çalışmalar…

Adamlar yeni versiyon diye yeni framework çıkarmışlar 😀
Paylaşımınız için teşekkürler hocam.
😂