Sonsuz kaydırıcının karmaşıklıkları

Özet: DOM öğelerinizi yeniden kullanın ve görüntü alanından uzakta olanları kaldırın. Geciken verileri hesaba katmak için yer tutucular kullanın. Sonsuz kaydırma aracının demosunu ve kodunu burada bulabilirsiniz.

İnternetin her yerinde sonsuz kaydırıcılar görünüyor. Google Müzik'in sanatçı listesi, Facebook'un zaman çizelgesi ve Twitter'ın canlı feed'i de bunlardan biridir. Ekranı aşağı kaydırıyorsunuz ve en alta varmadan önce yeni içerik sanki bir garip gibi görünüyor. Bu, kullanıcılar için sorunsuz bir deneyim sunar ve ilgi çekiciliğini görmek kolaydır.

Bununla birlikte, sonsuz kaydırma çubuğunun ardındaki teknik zorluk, göründüğünden daha zor. Doğru ThingTM'i yapmak istediğinizde karşılaştığınız çok sayıda sorun var. İçerik, altbilgiyi uzağa ittiği için altbilgideki bağlantılara pratikte ulaşılamaması gibi basit şeylerle başlar. Ancak sorunlar daha da daha zor hale gelir. Bir kişi telefonunu dikey yönden yatay yöne çevirdiğinde yeniden boyutlandırma etkinliğini nasıl ele alırsınız veya liste çok uzadığında telefonunuzun durmasını nasıl engellersiniz?

Doğru şeyTM

Bu durumun, performans standartlarını korurken tüm bu sorunların yeniden kullanılabilir bir şekilde üstesinden gelme yöntemini gösteren bir referans uygulama bulmak için yeterli neden olduğunu düşündük.

Hedefimize ulaşmak için 3 teknik kullanacağız: DOM geri dönüşümü, mezar taşları ve kaydırma demirleme.

Demo örneğimiz, mesajlar arasında gezinmek için Hangouts benzeri bir sohbet penceresi olacak. İhtiyacımız olan ilk şey sohbet mesajları için sonsuz bir kaynaktır. Teknik olarak, mevcut sonsuz kaydırıcıların hiçbiri gerçekten sonsuz değildir, ancak bu kaydırıcılara aktarılmak için kullanılabilecek veri miktarıyla da olabilirler. İşinizi kolaylaştırmak için bir grup sohbet mesajını sabit olarak kodlayıp rastgele mesaj, yazar ve resim eklerini seçeceğiz. Ayrıca gerçek ağa biraz daha benzer davranmak için yapay gecikme uygulayacağız.

Chat uygulaması ekran görüntüsü

DOM geri dönüşümü

DOM geri dönüşümü, DOM düğüm sayısını düşük tutmak için sık kullanılmayan bir tekniktir. Genel fikir, yenilerini oluşturmak yerine önceden oluşturulmuş DOM öğelerini ekran dışında kullanmaktır. DOM düğümlerinin kendileri ucuzdur ancak her biri bellek, düzen, stil ve boyama açısından ekstra maliyet getirdiğinden ücretsiz değildir. Web sitesinin yönetilemeyecek kadar büyük bir DOM'si varsa düşük donanımlı cihazlar tamamen kullanılamaz hale gelirse fark edilir bir şekilde yavaşlar. Ayrıca, stillerinizin her geçiş ve yeniden uygulama işleminin (bir düğüme sınıf eklendiğinde veya düğümden kaldırıldığında tetiklenen bir işlem) daha büyük bir DOM ile daha pahalı hale geleceğini de unutmayın. DOM düğümlerinizin geri dönüştürülmesi, toplam DOM düğümlerinin sayısını önemli ölçüde azaltarak tüm bu süreçleri hızlandıracağımız anlamına gelir.

İlk engel, kaydırmadır. Herhangi bir zamanda DOM'deki tüm kullanılabilir öğelerin küçük bir alt alt grubuna sahip olacağımızdan, tarayıcının kaydırma çubuğunun teorik olarak orada bulunan içerik miktarını doğru bir şekilde yansıtmasını sağlayacak başka bir yol bulmamız gerekir. Öğeleri içeren öğeyi (podyum) istenen yüksekliğe sahip olmaya zorlamak için bir dönüşüme sahip 1x1 piksel boyutunda bir koruyucu öğe kullanacağız. Uçak pistinin kendi katmanının tamamen boş olmasını sağlamak için, podyumdaki her öğeyi kendi katmanlarına yükselteceğiz. Arka plan rengi de, hiçbir şey de yok. Pist katmanı boş değilse tarayıcının optimizasyonları için uygun olmaz ve grafik kartımızda birkaç yüz bin piksel yüksekliğindeki bir doku depolamamız gerekir. Mobil cihazlarda kesinlikle uygun değildir.

Ekranı kaydırdığımızda, görüntü alanının pistin sonuna yeterince yaklaşıp yaklaşmadığını kontrol ederiz. Böyle bir durumda, koruyucu öğeyi hareket ettirerek ve görüntü alanından ayrılan öğeleri pistin alt kısmına taşıyarak pistin süresini uzatır ve bunları yeni içerikle doldururuz.

Koşu } }

Aynı durum, diğer yönde kaydırma için de geçerlidir. Ancak kaydırma çubuğu konumunun tutarlı kalması için, uygulamamızda hiçbir zaman platformu küçültmeyiz.

Mezar taşları

Daha önce belirttiğimiz gibi, veri kaynağımızın gerçek dünyadaki bir şey gibi davranmasını sağlamaya çalışıyoruz. Ağ gecikmesi ve diğer tüm özellikler. Diğer bir deyişle, kullanıcılarımız esnek kaydırmayı kullanırsa elimizde veri bulunan son öğeyi kolayca kaydırabilirler. Bu durumda, bir mezar taşı öğesi (bir yer tutucu) yerleştiririz. Bu öğe, veriler geldiğinde asıl içerikle değiştirilir. Mezar taşları da geri dönüştürülmüştür ve yeniden kullanılabilir DOM öğeleri için ayrı bir havuza sahiptir. Bir mezar taşından içerikle dolu öğeye güzel bir geçiş yapabilmemiz için buna ihtiyacımız var. Aksi takdirde, kullanıcı açısından çok rahatsız edici olabilir ve gerçekte odaklanılan şeyin kaybedilmesine yol açabilir.

Öyle bir
tomb. Çok taş. Vay canına!

Burada ilginç bir zorluk, öğe başına veya eklenen resimdeki metin miktarlarının farklı olması nedeniyle gerçek öğelerin mezar taşı öğesinden daha büyük bir yüksekliğe sahip olmasıdır. Bu sorunu çözmek için, veri her geldiğinde ve görüntü alanının üzerinde bir mezar taşı değiştirildiğinde mevcut kaydırma konumunu ayarlayacağız. Böylece, kaydırma konumunu piksel değeri yerine bir öğeye sabitleyeceğiz. Bu kavrama kaydırma sabitleme denir.

Kaydırma sabitleme

Kaydırma sabitlememiz, hem mezar taşları değiştirilirken hem de pencere yeniden boyutlandırıldığında (cihazlar döndürülürken de geçerli olur) etkinleşir. Görüntü alanında en üstteki görünür öğenin ne olduğunu bulmamız gerekir. Bu öğe yalnızca kısmen görülebildiğinden, ofseti de görüntü alanının başladığı öğenin üst kısmından saklayacağız.

Kaydırma sabitleme şeması.

Görüntü alanı yeniden boyutlandırılırsa ve modelde değişiklikler olursa kullanıcıya görsel olarak aynı hissi veren bir durumu geri yükleyebiliriz. Kazanın! Yalnızca yeniden boyutlandırılan bir pencere, her öğenin yüksekliğini değiştirmiş olabileceği anlamına gelir. Peki, sabit içeriğin ne kadar aşağıya yerleştirilmesi gerektiğini nasıl bilebiliriz? Biz hayır! Bunu öğrenmek için, sabit öğenin üzerindeki her öğeyi düzenlememiz ve tüm yüksekliklerini toplamamız gerekir. Bu durum, yeniden boyutlandırma sonrasında önemli bir duraklamaya neden olabilir ve bunu istemeyiz. Bunun yerine, yukarıdaki her öğenin mezar taşıyla aynı boyutta olduğunu varsayarak kaydırma konumumuzu buna göre ayarlarız. Öğeler podyuma kaydırılırken kaydırma konumumuzu ayarlıyoruz. Bu sayede düzen çalışmasını etkin bir şekilde ihtiyaç duyulduğu zamana ertelemiş oluyoruz.

Düzen

Önemli bir ayrıntıyı atladım: Düzen. Bir DOM öğesinin her geri dönüşümü, normalde pistin tamamını oluşturur. Bu da bizi saniyede 60 karelik hedeflerimizin çok altına düşer. Bunu önlemek için düzen yükünü kendimize taşıyor ve dönüşümler ile tamamen konumlandırılmış öğeleri kullanıyoruz. Bu şekilde, gerçekte yalnızca boş bir alan varken, pistin yukarısındaki tüm öğelerin hâlâ yer kapladığını varsayabiliriz. Düzen işlemini kendimiz yaptığımız için, her öğenin sonunda bulunduğu konumları önbelleğe alabiliriz ve kullanıcı geriye doğru kaydırdığında doğru öğeyi önbellekten hemen yükleyebiliriz.

İdeal olarak, öğeler DOM'ye bağlandıklarında yalnızca bir kez yeniden boyanır ve pistteki diğer öğelerin eklenmesi veya kaldırılmasından etkilenmez. Bu mümkün ama sadece modern tarayıcılarla mümkün.

Yeni tasarımlar

Kısa süre önce, Chrome'un CSS Containment özelliği için desteği eklendi. Bu özellik, geliştiricilerin tarayıcıya bir öğenin düzen ve boyama işleri için sınır olduğunu söylemesine olanak tanır. Biz burada kendi düzenimizi yaptığımızdan, kontrol altına alma konusunda başlıca bir uygulamadır. Podyuma bir öğe eklediğimizde, diğer öğelerin geçişten etkilenmesine gerek olmadığını biliyoruz. Her öğe contain: layout olmalıdır. Web sitemizin geri kalanını da etkilemek istemediğimizden, pistin kendisi de bu stil yönergesini de almalıdır.

IntersectionObservers'i, kullanıcının öğeleri geri dönüştürmeye ve yeni veriler yüklemeye başlamamıza yetecek kadar kaydırdığını algılayan bir mekanizma olarak da değerlendirdiğimizi göz önünde bulundurduk. Bununla birlikte, IntersectionObservers'ların yüksek gecikmeli (requestIdleCallback kullanan gibi) olduğu belirtilir. Bu nedenle, IntersectionObservers kullanıldığında, hiç olmadığı kadar duyarlı görebiliriz. Kaydırma etkinlikleri "en iyi çaba" temelinde dağıtıldığı için scroll etkinliğini kullanan mevcut uygulamamızda bile bu sorun yaşanıyor. En sonunda Houdini'nin Birleşik İş Akışı bu sorun için yüksek kaliteli bir çözüm olacaktır.

Hâlâ mükemmel değil

Şu anki DOM geri dönüşümü uygulamamız, sadece ekranda üzerinde bulunan öğelerle ilgilenmek yerine görüntü alanından geçen tüm öğeleri eklediği için ideal değildir. Yani, gerçekten hızlı bir şekilde kaydırma yaptığınızda, Chrome'da düzen ve boyama için o kadar çok emek harcıyorsunuz ki buna ayak uyduramazsınız. Arka plandan başka bir şey görmeyeceksiniz. Dünyanın sonu değil, ama kesinlikle geliştirilmesi gereken bir şey.

Mükemmel bir kullanıcı deneyimini yüksek performans standartlarıyla bir araya getirmek istediğinizde basit sorunların ne kadar zor hale geldiğini anlayacağınızı umuyoruz. Progresif Web Uygulamaları, cep telefonlarında temel deneyimler haline gelirken bu daha önemli hale gelecek ve web geliştiricilerinin performans kısıtlamalarına uyan kalıplar için yatırım yapmaya devam etmesi gerekecek.

Tüm kodlar depomuzda bulunabilir. Yeniden kullanılabilir durumda tutmak için elimizden geleni yaptık, ancak npm'de veya ayrı bir depo olarak gerçek bir kitaplık olarak yayınlamayacağız. Birincil kullanım amacı eğitimdir.