Front end Development
Blocking Rendering’in Sonu: Concurrent Mode
October 10, 2019Geçtiğimiz hafta React Ekibi tarafından paylaşılan bir makale; komünite ve UI geliştiricileri tarafından oldukça heyecanla karşılandı. Bu heyecanın nedeni de; genel olarak UI kütüphanelerinin çalışma prensiplerinin yarattığı en büyük problemlerden birisinin ortadan kaldırmak adına yapılan çalışmalar. “Blocking Rendering” olarak isimlendirilen problem, React’ın yeni bakış açısıyla tasarladığı “Concurrent Mode” ile ortadan kalkıyor. Peki, “Blocking Rendering” nedir, “Concurrent Mode” bu problemi ortadan nasıl kaldırıyor? Birlikte inceleyelim.
Blocking Rendering
Günümüzde UI kütüphaneleri, tarayıcıyı senkronize şekilde günceller. Örneğin bir ekranı açmak istediğimizde, UI kütüphanesi DOM’daki bu değişiklikleri ekrana tek seferde yansıtmak ister. Örneğin içerisinde liste olan bir ekranı açmak için, liste componentini render etmeye başlar, bu render işlemi bitene kadar da ekranda başka hiçbir şey yapılmaz. Şimdi bu listenin 500.000 elemanı olduğunu düşünelim. Ekranda herhangi bir etkileşim yaratabilmek için, maalesef bu listedeki tüm elemanlar render olana kadar beklemek zorundayız.
Peki bu listenin üzerine bir de filtre eklediğimizi düşünürsek ne olur? Filtrenin çalışacağı text input içine yazdığımız herhangi bir harfin gözükmesi için, bu devasa bekleme süresi tekrar devreye girer. Bu bekleme ve ekranda beliren sürekli takılarak çalışma hissi, kullanıcı deneyimini tamamen olumsuz bir algıya dönüştürebilecek problemler silsilesine yol açmış olur.
Interruptible Rendering
Bu problemleri şimdiye dek hiç yaşamadık mı ya da görmemezlikten mi geldik? Tabii ki hayır. Bir şekilde bu problemleri “halı altına süpürmek” için hali hazırda “Debouncing” ve “Throttle” gibi yöntemleri kullanıyorduk. Bunların ne olduğuna değinecek olursak; birden fazla yapılan sıralı fonksiyon çağrılarını teke indirmek için kullandığımız yöntem Debouncing, fonksiyon çağrısını etkileşimden bir süre sonra(delay) yapmak için kullandığımız yöntem de Throttling oluyor. Fakat bu yöntemler, filtre için text input içerisine bir şeyler yazarken listenin aynı kalmasının ya da gücü sınırlı cihazlarda takılma, bekleme gibi sorunların devam etmesinin önüne geçemiyor.
Çünkü rendering başladığı andan itibaren sonuna dek kesilemiyor. Bu nedenle text input içine yazdığımız harf her dokunuşta güncellenemiyor. Hangi UI kütüphanesini kullanırsanız kullanın, eğer kütüphane blocking rendering kullanıyorsa, büyük oradanki componentlerin yaşattığı bu sıkıntının da çözümü de kolay olmuyor.
Bu sorunlarla baş etmekte zorlanan Facebook ekibi, artık React kütüphanesinde Concurrent Mode ile kütüphanenin temelindeki limitlemeleri ortadan kaldırarak rendering’i interruptible hale, yani önceliklere göre araya girebilecek hale getiriyor.
Concurrent Mode
Concurrent Mode, React tarafından;
“Concurrent Mode is a set of new features that help React apps stay responsive and gracefully adjust to the user’s device capabilities and network speed.” şeklinde açıklanmış. Bu tanımı, “React uygulamasını, kullanıcının cihaz yetenekleri ile ağ hızına göre her zaman cevap verebilir ve detaylıca ayarlanabilir hale getirecek özellikler seti.” olarak çevirsek sanırım hatalı olmaz. Concurrent Mode’u anlamaya çalışırken; teorik ve okunduğunda aslında çok da bir şey ifade etmeyen bu tanımdan ziyade, “önceliklendirme” kavramı ile birlikte düşünmenizi tavsiye ederim.
Yazının başında da bahsettiğim gibi Concurrent Mode olmadan React, tamamen bitene kadar rendering işine devam ediyordu ve rendering bitmeden diğer işlere sıra gelmiyordu.
Concurrent Mode ile React ise, hali hazırda rendering işi devam ederken eğer daha öncelikli bir iş gelirse, mevcut rendering’i kesebiliyor. Öncelikli işi araya alıp, bitirdikten sonra da rendering’e devam edebiliyor duruma geliyor. Yani bir bakıma, tamamen senkron yapıdan, asenkron olabilen bir rendering algoritması bizi bekliyor.
Bu öncelikli işler neler olabilir?
- Tarayıcının herhangi bir ihtiyacı
- React’ın render’a ihtiyaç duyan bir güncellemesi
- Uygulamanın içinden ya da dışından çağırılacak başka bir iş
Bununla birlikte, başka bir önemli özellik daha var. Aslında o da günümüzdeki bir çok UI kütüphanesinin davranış biçimlerinden birisine efektif çözüm oluyor. Örneğin kullanıcı “Ana Sayfa” üzerinde beklerken, “Siparişlerim” butonuna tıklayarak o ekrana gitmek istiyor. Kullanıcı, bu sırada geliştirici ekibin kararına göre 2 farklı davranıştan birini görüyor. Uygulama ya kullanıcıya tüm bilgiler gelmeden örnek bir boş sayfa gösteriyor, ya da bilgilerin yavaşça dolmasını sağlayarak ekranın kullanıcı görürken şekillendiriyor.
React’ın yeni Concurrent Mode’u ile artı kullanıcı butona bastığı anda bellekte gidilmek istenen sayfayı render ederken, kullanıcı hali hazırda bulunduğu sayfada kalmaya devam ediyor. Ne zaman servis çağrıları ve resim yüklemesi gibi zaman alan işler biterse, kullanıcıya diğer sayfayı tamamen dolu haliyle o zaman açıyor. Bu sayede kullanıcı hiçbir zaman önünde şekillenen bir sayfa görmüyor. Bununla birlikte sayfa içerisinde “Loading” imajı da eklenirse, sorunsuz bir kullanıcı deneyimi halini almış alıyor. Bu sayede uygulamanın akışı ve cevap verebilirliği büyük ölçüde artıyor.
Bu günümüz koşullarında başka çözüm yolları ile yapılabilir olsa da, yönetimi zor ve karmaşık olan bir hale gelebiliyor. React Concurrent Mode, React içerisinde built-in yani dahili olarak gelerek bu sorunları merkezde çözmeyi hedefliyor.
Kod Örneği
import {
useState,
commonUpdate,
urgentUpdate
} from "sample-react";
function SlowAndLowPriorityComponent() {
const [someData, changeData] = useState(0);
return (
<div>
<BigComponentThatTakesVeryLongToRender someProp={someData} />
<button
onClick={() => {
commonUpdate(() =>
changeData(prevData => prevData + 1)
);
}}
>
Uzun süren ve düşük öncelikli güncelleme
</button>
</div>
);
}
function FastAndHighPriorityComponent() {
const [someData, changeData] = useState(0);
return (
<div>
<SmallComponentThatRendersFast someProp={someData} />
<button
onClick={() => {
urgentUpdate(() =>
changeData(prevData => prevData + 1)
);
}}
>
Hızlı ve acil güncelleme
</button>
</div>
);
}
function App() {
return (
<div>
<SlowAndLowPriorityComponent />
<FastAndHighPriorityComponent />
</div>
);
}
// Eğer kullanıcı önce SlowButLowPriorityComponent butonuna,
// ve sonrasında FastAndHighPriorityComponent butonuna tıklarsa;
// React SlowButLowPriorityComponent'inin renderingini durdurup,
// FastAndHighPriorityComponent'inin renderingini (yeni state ile)
// tamamlar. Sonrasında SlowButLowPriorityComponent değişikliğine
// devam eder.
Concurrent Mode’a Ne Denli İhtiyacımız Var?
Genel olarak altyapısal bir yeni özellik olan Concurrent Mode için, bana kalırsa React tabanlı uygulamaların çoğu en azından aciliyetli olarak kullanım gereksinimi duymayacak. Yani zorunlu bir güncelleme ya da kullanım zorunluluğu duyulmayacak.
Ama uygulamasını ihtiyaçlarına göre, kütüphanenin gücünü de arkasına alarak daha güçlü hale getirmek isteyen herkes için önemli bir özellik. Sonuç olarak state yönetimini asenkron hale getirmek için müthiş bir yenilik. Özellikle içerisinde sayfa sayısı ve işlem seti çok geniş olan kurumsal uygulamalar için oldukça verimli bir yaklaşım olması muhtemel.
Kütüphanenin oldukça “advanced” olan bu yeni özelliğinin, tamamen Facebook’un ihtiyaçları dolayısıyla geliştirildiğini de belirtmek lazım. Bu özelliğin komünite ile paylaşılması da oldukça sevindirici.
Özetlemek Gerekirse
React Concurrent Mode, artık eş zamanlı olarak birden fazla state güncellenmesine olanak tanıyor.
Concurrency;
- CPU’ya bağlı güncellemeler için; (Yeni Dom elemanı yaratmak ya da component kodunu çalıştırmak gibi) daha acil güncelleme hali hazırda başlamış olan rendering’i kesebilir
- Giriş/Çıkış’a bağlı güncellemeler için; (Ağ bağlantısı ile kod ya da data almak gibi) bütün veri hazır olmadan önce bellekte render başlatabilir ve boş ya da hazır olmayan ekranları görmekten kurtarır
şeklinde yorumlanabilir.
Henüz herhangi bir React versiyonunda yer almayan bu yeni özelliğin, hangi versiyonla birlikte kullanılmaya başlanacağı tarihle ilgili bilgi de paylaşılmadı. Bu nedenle nihai bir sonuç olmadığı için, önümüzdeki süre zarfında altyapısında ve bazı yaklaşımlarında değişiklikler olması da muhtemel.
Kaynaklar:
- https://reactjs.org/docs/concurrent-mode-intro.html
- https://reactjs.org/docs/concurrent-mode-patterns.html
- https://reactjs.org/docs/concurrent-mode-suspense.html
- https://hswolff.com/blog/why-is-react-concurrent-mode-exciting/
- https://medium.com/@rossbulat/react-lazy-suspense-and-concorrent-react-breakdown-with-examples-2758de98cb1c
- https://dev.to/pomber/about-react-suspense-and-concurrent-mode-21aj
- https://hub.packtpub.com/react-conf-2019-concurrent-mode-preview-out-css-in-js-react-docs-in-40-languages-and-more/
- https://codesandbox.io/s/54qzv6m8ql?from-embed
Author: Efecan Tekin