Derinlemesine yazılım eğitimleri için kanalımı takip edebilirsiniz...

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, @defer ile 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 🙂
Angular 17 - @defer Deferrable ViewsGö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, @defer içeriği lazy loading’le yüklerken; @placeholder, @loading ve @error eagerly 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>
        }
    

    @defer seçeneğinin when koşulu built-in gelen *ngIf direktifinin davranışına benzetilebilir. İkisinin arasındaki radikal fark, *ngIf ile yapılan kontrolde boolean değer false olduğu taktirde ilgili template görselden kaldırılırken, @defer‘ın when koş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 immediate koş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
    Angular 17 - @defer Deferrable Viewson hover koşulu ile kullanıcının template reference variable ile belirtilen html nesnesinin üzerine geldiğinde @defer iç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 şekilde on interaction ile de kullanıcının belirtilen html nesnesiyle click ya da keydown event’leriyle etkileşime girdiği taktirde @defer iç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 @defer bloğ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…

Bunlar da hoşunuza gidebilir...

2 Cevaplar

  1. Görkem dedi ki:

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

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir