JavaScript’e Signals ekleme önerisi
(github.com/proposal-signals)- TC39’un JavaScript Signals önerisi, UI durumu ve türetilmiş durumu verimli biçimde izlemek için reaktif ilkel değerleri standartlaştırmaya yönelik erken aşama bir yönelim ve şu anda Stage 1 düzeyinde bir taslak
- Öneri, uygulama geliştiricilerinin doğrudan kullanacağı yüzey API’sinden çok, framework’lerin paylaşabileceği Signal grafiğinin çekirdek anlambilimi ile otomatik izleme mekanizmasına odaklanıyor
Signal.State,Signal.Computed,Signal.subtle.Watchertemel API’ler; hesaplamalar ise lazy evaluation, önbellekleme, otomatik bağımlılık takibi ve glitch-free çalışmayı hedefliyor- Yerleşik Signals’ın amacı; Angular, Ember, MobX, Preact, Qwik, Solid, Svelte, Vue gibi çeşitli framework’ler arasında birlikte çalışabilirliği artırmak ve DevTools için hata ayıklama ile performans analizi desteğinin önünü açmak
- Öneri grubu, Stage 2 öncesinde birden çok prodüksiyon düzeyinde polyfill, framework entegrasyonu, büyük ölçekli uygulama doğrulaması ve performans benchmark’ı yapmayı planlıyor; standardizasyona ulaşması en az 2~3 yıl veya daha fazla sürebilir
JavaScript Signals önerisinin konumu
- JavaScript Signals, TC39 sürecinde Stage 1 önerisi olarak tanıtılıyor
- Mevcut belge, ES2015 öncesinde
Promisestandardizasyonundan önceki Promises/A+’a benzer şekilde, JavaScript ekosisteminde ortak yönü hizalama girişimi olarak görülüyor - Doğrudan denenebilecek bir polyfill sunuluyor
- Öneri şampiyonları ve asıl yazarlar, çeşitli framework ve kütüphanelerden gelen tasarım girdilerine dayanarak mevcut taslağı oluşturdu
Standardizasyonun hedeflediği sorun
- Karmaşık UI’ler değerleri saklamak, hesaplamak, geçersiz kılmak, senkronize etmek ve görünüm katmanına itmek zorunda; Signals ise bu tekrar eden işler için durum yönetimi altyapısı sağlamayı amaçlıyor
- Vanilla JS örneğinde
counter,isEven,parity,renderdoğrudan birbirine bağlanıyor ve şu sorunlar ortaya çıkıyor- Durum ile render sistemi sıkı biçimde bağlanıyor
counter2’den 4’e değiştiğinde olduğu gibiparitydeğişmese bile gereksiz hesaplama ve render tetikleniyor- Başka UI parçaları
counter,isEven,parityiçinden yalnızca bazılarına abone olmak istediğinde, manuel abonelik ve abonelikten çıkma yönetimi karmaşıklaşıyor - Birden fazla aşamaya pub/sub eklendiğinde boilerplate ve abonelik bookkeeping artıyor, bellek sızıntısı riski doğuyor
- Signals tabanlı örnek,
Signal.StateveSignal.Computedkullanarak değerleri, hesaplamaları ve yan etkileri tek bir modelde ele alıyor- Manuel abonelik gerekmiyor
- Hesaplanmış Signal, hangi Signal’lara bağlı olduğunu otomatik buluyor
- Hesaplamalar yalnızca değere açıkça ihtiyaç duyulduğunda çalışıyor
- Hesaplanmış Signal son değeri önbelleğe alıyor
Önerinin temel API’si
Signal<T>,get(): Tiçeren okunabilir bir değer olarak tanımlanıyorSignal.State<T>yazılabilir bir Signal- Kurucu, başlangıç değeri ve seçenekleri alıyor
- Değer
get()ile okunuyor,set(t)ile değiştiriliyor
Signal.Computed<T>, başka Signal’lara dayanan bir hesaplanmış Signal- Callback’in döndürdüğü değerle hesaplanıyor
- Bağımlılıkları otomatik izliyor
- Değer lazy olarak hesaplanıyor ve önbelleğe alınıyor
Signal.subtle, framework yazarlarına veya DevTools uygulamalarına daha yakın gelişmiş API’leri içeriyoruntrack(cb), Signal’ı izleme olmadan okumayı sağlıyorcurrentComputed(), o anda izlenmekte olan computed Signal’ı döndürüyorintrospectSources,introspectSinks,hasSinks,hasSourcesgrafik gözlemi için API’lerWatcher, Signal değişikliklerini algılayarak framework düzeyinde effect ve scheduling uygulamaları için temel sağlıyor
SignalOptions<T>, kullanıcı tanımlı karşılaştırma işleviequalsilewatched/unwatchedhook’larını destekliyor
Çalışma biçimi ve yürütme modeli
- Signal, zaman içinde değişebilen bir veri hücresini temsil ediyor ve
stateya dacomputedolarak ayrılıyor - Hesaplanmış Signal, çalışırken okuduğu Signal’ları otomatik kaydediyor ve sonraki okumada önceki bağımlılıkların değişip değişmediğini kontrol ediyor
- Hesaplama pull-based
- Bağımlılıklar değişse bile hemen yeniden hesaplama yapılmıyor
- Biri
.get()ile okuduğunda gerekirse yeniden hesaplanıyor
- State Signal yazımları senkron biçimde yansıtılıyor
.set()sonrasında o değere bağlı bir computed Signal okunursa gerekirse hemen yeniden hesaplanıyor- Yerleşik batching yok
- Watcher’ın
notifycallback’i.set()sırasında senkron olarak çalışabiliyor- Ancak
notifyiçinde Signal okuma ya da yazma yapılamıyor - Asıl okuma/yazma işlemleri daha sonra planlanmalı
- Ancak
- Computed Signal callback’i istisna fırlatırsa, bu istisna da değer gibi önbelleğe alınıyor ve Signal yeniden okunduğunda tekrar fırlatılıyor
Standardizasyon motivasyonu
- Her framework’ün Signal uygulaması kendi otomatik izleme mekanizmasına sahip olduğundan, model, bileşen ve kütüphaneleri framework’ler arasında paylaşmak zorlaşıyor
- Önerinin amacı reaktif modeli render görünümünden ayırmak
- Geliştiricinin render teknolojisini değiştirdiğinde UI dışı kodu yeniden yazmak zorunda kalmaması hedefleniyor
- Birden çok bağlamda paylaşılabilecek reaktif modellerin JavaScript ile kurulabilmesi amaçlanıyor
- Performans ve bellek açısından, yerleşik uygulamanın JS tabanlı uygulamalara göre küçük sabit katsayılarda daha verimli olabileceği, ancak motorun sihirli biçimde algoritmayı değiştirmeyeceği özellikle belirtiliyor
- DevTools açısından, yerleşik Signals şu bilgileri daha iyi gösterebilir
- Computed Signal zincirinin call stack’i
- Signal’lar arasındaki referans grafiği
- Bellek kullanımı hata ayıklaması için gereken bağımlılık ilişkileri
- Standart kütüphaneye dahil edilirse, bundle boyutunun küçülmesi, kararlılık ve kalite artışı, projeler arasında ortak bir sözlük oluşması gibi yan etkiler de bekleniyor
Tasarım hedefleri ve kısıtlar
- Çekirdek işlevler; yazılabilir Signal, hesaplanmış Signal, dirty duruma tepki verme, framework’ün kendi scheduling mekanizması,
untrackve birden çok kod tabanının birleşimini içeriyor - Hesaplanmış Signal’lar glitch-free olmayı hedefliyor
- Gereksiz hesaplamaları önlemek için grafiğin potansiyel olarak dirty bölümleri topolojik sırayla yürütülüyor
- Tekrarlı hesaplamalar ortadan kaldırılmaya çalışılıyor
- Framework’lerin kendi scheduling’ini yapabilmesi için Promise tarzı yerleşik zorunlu scheduling eklenmiyor
- Senkron tepki callback’lerinin kötüye kullanımını engellemek için Watcher’ın
notifyiçinde Signal okuma ve yazma yasaklanıyor untrack, güvenli olmayan bir kaçış kapısı olarak değerlendiriliyor- İzleme olmadan okunan bir Signal hesaplama sonucunu etkiliyorsa, bu Signal değiştiğinde computed Signal güncellenmeyebilir
- API, genel uygulama geliştiricileri için özellikle ergonomik olmaktan çok framework uygulamalarının temeli olmayı önceliklendiriyor
effect ve Watcher
- Öneride
effect()gibi yerleşik bir işlev yok - Effect scheduling; framework render döngüsü, disposal ve sahiplik yönetimiyle iç içe olduğundan, JavaScript standart API’si bunu doğrudan çözmüyor
- Bunun yerine
Signal.subtle.Watcher, effect uygulamaları için düşük seviyeli bir temel sunuyor- İzlenen Signal’ların bağımlılıkları değiştiğinde
notifyçağrılıyor getPending()ile hâlâ dirty olan Signal’lar görülebiliyor- Dispose gerektiren effect’ler
unwatchile temizlenmeli
- İzlenen Signal’ların bağımlılıkları değiştiğinde
- Watcher’ın izlediği Signal’lar, iç durumlarına erişilebildiği sürece yaşamaya devam edebileceğinden, effect temizliği sırasında
Watcher.prototype.unwatchçağrısı gerekiyor
Mevcut taslakta olmayan işlevler
- Async, mevcut modele dahil değil
- Signals her zaman senkron olarak değerlendirilebilen değerler olarak ele alınıyor
- Loading durumunu istisna ile modellemenin bazı yolları bulunuyor; iyileştirme tartışmaları Issue #30 içinde yer alıyor
- Transactions da dahil değil
- Ekran geçişlerinde “from” durumu ile “to” durumunu aynı anda korumak, Signal grafik durumunu fork etme sorununu doğuruyor
- İlgili tartışma Issue #73 içinde yer alıyor
- Bazı convenience methods de mevcut taslakta bulunmuyor
- Eksik kalan bu işlevler, framework’ler arasında yeterli uzlaşı olmaması ve üst katmanlarda etrafından dolaşılabilmesi nedeniyle dışarıda bırakıldı; ancak prototip sonrasında yeniden değerlendirilebilir
Geliştirme planı ve standardizasyon takvimi
- Bu öneri, Nisan 2024’te TC39 Stage 1 gündemine alınmış durumda; belgede mevcut durumun pratikte Stage 0 gibi de görülebileceği belirtiliyor
- Stage 2 önerilmeden önce şu çalışmalar planlanıyor
- Birden fazla prodüksiyon düzeyinde polyfill geliştirilmesi
- Çeşitli framework testleri ve test262 tarzı testlerin geçilmesi
- Kapsamlı bir signal/framework benchmark seti ile performans doğrulaması
- Temsili çeşitli JS framework’lerine ve bazı büyük ölçekli uygulamalara önerilen API’nin entegre edilmesi
- API’nin genişletilebilirliğinin anlaşılması ve nelerin dahil edileceğine karar verilmesi
- Öneri grubu, yanlış biçimde tasarlanmış Signals’ın çok erken standartlaşmasını önlemek için temkinli ilerlemek istiyor
- FAQ, standart Signals’ın tarayıcıların genelinde polyfill olmadan kullanılabilir hale gelmesinin en az 2~3 yıl süreceğini öngörüyor
- Mevcut polyfill bugün kullanılabilir, ancak inceleme sürecinde API değişebileceği için kararlılığına güvenilmemesi tavsiye ediliyor
FAQ’de özetlenen kullanım modeli
- Yerleşik Signals, render teknolojisinden bağımsız
- VDOM kullanan Preact, native DOM kullanan Solid, karma yaklaşım kullanan Vue gibi farklı modellerin hepsi mümkün görülüyor
- Uygulama geliştiricileri için Signals’ı çoğunlukla framework üzerinden kullanmak daha uygun
- Framework; Watcher,
untrack, ownership, disposal ve DOM render scheduling işlerini yönetiyor
- Framework; Watcher,
- SSR, hydration ve resumability ile birlikte kullanılabiliyor
- Qwik, Signals’ı bu özelliklerle birlikte kullanıyor; öneri tarafı da Qwik’in resumable Signals yapısının State ve Computed birleşimiyle modellenebileceğini düşünüyor
- Signals ile
Proxybirbirini tamamlıyor- Proxy, sığ nesne işlemlerini yakalıyor; Signals ise veri hücrelerinin bağımlılık grafiğini düzenliyor
Proxyarkasında Signals kullanmak, iç içe reaktif yapıları daha ergonomik hale getirebilir
- Signals, stream değil; mevcut değeri temsil eden hücreler
- Bir State Signal’a art arda iki kez yazılıp başka hiçbir işlem yapılmazsa, ilk yazım computed Signal ya da effect tarafından hiç görülmeyebilir
- Belgede bu durum, glitch-free yürütmenin karşı ucundaki bir özellik olarak değerlendiriliyor; stream için async iterable veya observable gibi başka yapıların daha uygun olduğu belirtiliyor
1 yorum
Hacker News yorumları
Saf JavaScript örneğinin aslında okuması ve kullanması daha kolay olduğunu düşünen bir tek ben miyim merak ediyorum
“Kurulum gürültülü ve boilerplate’i çok” deniyor ama signals örneği de aynı derecede gürültülü ve boilerplate’i fazla görünüyor; üstelik yeni başlayanların anlaması zor yeni bir kavram da ekliyor
“counter 2’den 4’e değiştiğinde parity değişmiyor ama gereksiz hesaplama ve render yapılıyor” argümanı bana erken memoization gibi geliyor
UI’ın başka bir bölümü counter güncellemelerine göre render etmek istiyorsa o strawman örneğinin uygun olmadığı doğru; o durumda signals, olay işleme, merkezi durum deposu (Redux türü) gibi başka yöntemler kullanılabilir
UI’ın başka bir bölümü yalnızca isEven ya da parity’ye bağlıysa, uygulamanın temel yapısı açısından yaklaşımı değiştirebilirsiniz; ama çoğu durumda böyle değil. “Yalnızca parity’ye bağlı bir render fonksiyonunun counter’a abone olması gerektiğini bilmesi gerekiyor” ifadesi de mutlaka haksız bir yük değil; saf hesaplama fonksiyonlarının girdileri anlamayı kolaylaştırma avantajı var
UI geliştirmede giderek daha çok kullanılan bir kavram olan signals standardizasyonunu denemek övgüye değer. Boilerplate’in ne kadar olduğu, olay sistemini doğrudan sizin mi yazmanız gerektiği gibi ayrıntı tartışmalarını bir kenara bırakırsak, birden fazla framework signals kullanıyorsa bunun bir nedeni olabilir ve zaman alsa da standartlaştırmayı denemeye değer
https://preactjs.com/guide/v10/signals
Preact’te signal, props veya context üzerinden ağaçta aşağı inerken yalnızca signal referansı iletiliyor; bileşenler değere değil signal’a baktığı için signal güncellendiğinde bileşeni yeniden render etmeyebilir. Gerçekten de doğrudan ağaçta
.valueya erişen bileşene gidilebilirAyrıca signal, değerin ne zaman erişildiğini ve ne zaman güncellendiğini izler; Preact’te bir bileşenin içinde signal’ın
.valuedeğerine erişirseniz, o signal değeri değiştiğinde bileşen otomatik olarak yeniden render edilirDeneyimime göre en büyük avantaj, reaktif durumu modülerleştirebilmek. Emredici stilde değişimleri izlemek için ek duruma ihtiyaç duyulur ve modülerlik soyutlamayla elde edilir. Yalnızca gerektiğinde kullanmak yeterli
Basit ama uygulanabilir bir örnek oluşturmak bir denge meselesi. Reaktivitenin açıkça fayda sağladığı durumlar genelde daha karmaşık olduğundan, bunları göstermek basit ama daha az uygulanabilir örneklere göre daha zor
JavaScript’e Promises eklenirken her yerde
new Promiseyazmak zorunda kalacağım diye itici gelmiştiGerçekte ise doğrudan
new Promiseyazdığım durumları iki elin parmaklarıyla sayabilirim. Bunun yerine özellikle üçüncü taraf kütüphanelerle çalışırken.then’i çok daha sık kullanır oldumSonuçta Promise’ın JavaScript’e eklenmesinin gündelik etkisi, üçüncü taraf kütüphanelerin sunduğu çeşitli özel davranışlar ve özellikler için oldukça basit, genel olarak sağlam ve neredeyse evrensel bir arayüz sağlaması oldu. Dosya okuma olsun, API isteği olsun, derleme adımı çıktısı olsun,
.then(res => …)yazınca zaten çalışabilir bir şeyin yarısına gelmişsiniz gibi hissediliyorBu Signal önerisi, reaktif UI framework’lerinin Kambriyen patlaması içinde benzer bir rol oynarsa desteklerim. Dahası, reaktivitenin UI dışına taşmasına da yardımcı olabilir. UI durumu olmayan şeyler için artımlı yeniden hesaplama yapan durum ağaçlarını sık sık hayal etmişimdir
new Promiseyazmak nadiren gerekiyorİlk Promise
.thenkullanımı, iç içe delegate’lerden büyük bir iyileştirmeydi ve basit zincirler için fena değil; ama koşula bağlı olarak farklı Promise’leri zincirlemek, belirli zincirlerde farklı hata işleme yapmak veya erken dönüş gerektiğinde kod çok daha zor okunur ve yönetilir hale gelebiliyorasync/await ile çağrıları Promise değilmiş gibi yazabilir, belirli Promise çağrılarının etrafına kolayca try/catch koyabilir ve erken dönüşü de doğal biçimde yapabilirsiniz
Bunun neden dilin bir parçası olması gerektiğini anlamıyorum. Kütüphane olarak yapılabiliyor ve zaten böyle kütüphaneler var. Küçük olduğu için koda dahil etmek de büyük bir yük değil; dile eklemek başlı başına bir hedef olmamalı
Mevcut JS UI kütüphanelerinin signals’ı çok iyi tasarladığı için bunun dilin bir parçası olması gerektiğini düşünmek kibirli bir yaklaşım. signals için farklı ödünleşimlere sahip pek çok uygulama var ve bunların hiçbiri JavaScript spesifikasyonunda özel bir yer edinmeyi hak etmiyor
Bu kütüphaneler signals kullanmadan önce sanal DOM kullanıyordu. Neyse ki sanal DOM JS’in bir parçası olmadı; signals’ın farkı ne? Farkı yok. Standartlaştırılması gerektiğine dair argüman, sanal DOM dönemindekinden bile daha zayıf
Web’i bozmadan artık istemediğimiz özellikleri kaldırmanın fiilen bir yolu olmayan bir runtime’a, moda olan her şeyi yığacak mıyız? Oldukça miyopça
Reaktif UI kazandı. Küçük uygulamalarda bile durum yönetimi yaparken karmaşıklığın patlaması, saf JS kullanmayı zorlaştıran temel şey. Benim için herhangi bir reaktif framework saf JS’ten daha iyi; öyleyse eksik bir yapı taşı olabilir
Aradan yaklaşık 10 yıl geçtiğine göre, standartlaştırılabilecek sınır noktasını düşünmenin zamanı geldi. Promise gibi doğru yapılırsa çok yaygın kullanım senaryolarının karmaşıklığını azaltabilir
Daha iyi değerlendirme, “mevcut reaktif framework’ler bu öneriyi kullanır mı?” diye sormaktır. Kullanmazlarsa nedenini, neyin eksik olduğunu, neyin gereksiz olduğunu ve diğer dillerin UI ile reaktivite yaklaşımlarından ne öğrenilebileceğini görmek gerekir. Dağınık deneyimi damıtmanın değeri var
Bu ihtiyacın kendisi tartışılabilir, ama standart kütüphane genişletilecekse popüler olanlara bakmak iyi bir yaklaşım gibi görünüyor
signals, sanal DOM’un yerine geçen bir şey değildir
Uygulamanın tamamına bir şey sinyallemek gerektiğinde event kullanılır
window.dispatchEvent(new Event('counterChange'));Ve uygulamanın tepki vermek isteyen herhangi bir bölümü şöyle abone olabilir
window.addEventListener('counterChange', () => { ... do something ... });Bu yöntemde sorun ne?
Event işleme çok kolay dağınık hale gelir. Daha derine bakmak için event bubbling ve propagation konularına bakın
Büyük uygulamalarda sağlam event işleme gerekir; bu da Angular, Vue gibi framework’lerin bugün pek görünür olmayan avantajlarından biridir
Framework olmadan standart event işleme API’sini olduğu gibi kullanmak istemezsiniz. Çok sayıda öğe için ekleme, silme, kopyalama, tetikleme, kaldırma, tek seferlik tetikleme gibi işleri yönetirken ciddi istenmeyen yan etkiler oluşabilir
signals ile farkı, sonuç değerinin yalnızca nihai tüketici değeri okuduğunda hesaplanmasıdır. Signal’a gerçek yazma anı ile asenkron render güncellemesi planlamasını ayırır; gözlemcinin yürüttüğü hesaplama zinciri render sırasında yalnızca bir kez çalışır
signal üzerinden gönderilen ara değerler kaybolur; bu yüzden onların içinde çok ilginç işler yapmak zordur ve aslında render döngüsünü koordine etmeye yönelik daha üst düzey bir soyutlama katmanına yakındır
Performansı da daha iyi olabilir. Örneğin iki değere bağlı bir hesaplama olduğunu düşünelim:
result = a ? b : 0ifadesinde a false ise b değişse bile yeniden hesaplamak gerekmez. signals’ta bu otomatik olur; geleneksel publish/subscribe ile ise epey kod gerekirTüm listener’ların böyle zincirleme tetiklemeler oluşturmayacağını garanti etmek de zordur
İnsanların onlarca yıldır durum takibini ve DOM güncellemelerini neden bu kadar zor bulduğunu anlamaya çalışıyorum
Elbette biraz disiplin gerekiyor, ama bana birkaç yılda bir çıkan çözümlerden çok daha basit geliyor. Backbone, Knockout, Angular, React, dilin kendisini değiştirme vb.; sanırım benim düşünme biçimim temelden farklı
Fonksiyon adlarında bile belli oluyor.
innerTexti güncellemeye “render” deniyor ama aslında render etmek değil. Olsa olsa bunu tarayıcı render eder; boyama ve ilgili diğer tüm işler için de aynı şey geçerli. En basit DOM fonksiyonlarından birini karmaşık hale getirmeye yönelik çaresiz bir çaba gibi geldiği için gerçekten şaşırtıcıDaha karmaşık hale gelince kolay değil
Programlamadaki ilerleme, iyi sonuçlar almak için gereken törensel ve katı disiplini ortadan kaldırma süreci olarak görülebilir
React'in bir sonraki evrim olduğunu söylemiyorum, ama signals kesinlikle doğru yönde atılmış bir adım
DOM'u veri durumuyla senkronize etmek başlı başına çok zor değil, ama bunu 60fps'te çok performanslı yapmak inanılmaz derecede zor. Özellikle de sızdırmayan ama aşırı zahmetli de olmayan bir API yaparken
Değişiklikleri canlı DOM ağacına dönüştürüp yansıtmak yerine, açıkçası oyunlardaki gibi canvas'a piksel çizmek daha kolay bile olabilir
Promises iyi bir başarı örneği, ama async/await olmasaydı mutlaka standartlaştırılması gerekmezdi
Mevcut taslağın Angular, Bubble, Ember, FAST, MobX, Preact, Qwik, RxJS, Solid, Starbeam, Svelte, Vue, Wiz vb. projelerin yazarları/bakımcılarının tasarımlarına dayandığı söyleniyor; mevcut kütüphane yazarlarının bu öneriye nasıl baktığını merak ediyorum. React'in listede olmaması da ilginç
Signals kanallara biraz benziyor, ama tek bir alıcı yerine yayın yapmasıyla farklılaşıyor. Bunu kullanıp web worker'ların
onMessagecallback'i yerine kanallarla iletişim kurabilmesi güzel olurdu. Özellikle Go'daki gibi signals/channels/promises üzerindeselectyapılabilirse, birden çok eşzamanlı mesajlaşma mekanizmasını callback'lerle yönetmeye göre sözdizimsel bir avantaj sağlar. Örneğin signals'ıPromise.anyiçine dahil edebilmek gibix instanceof Promisedoğrudan çalışmaz. Benim kütüphanemdekithenmetodu catch callback'i alıyor da başka bir kütüphane almıyorsa, sessizce birlikte çalışmazlar ve bunu tespit etmenin de bir yolu yoktur.finallyne zaman çalışır? Callback'lerin ne kadar asenkron çalışacağı konusunda nasıl bir beklentiniz olabilir?Standart olmazsa Promise kullanan her kütüphane kendi polyfill'ini getirmek zorunda kalır. Çünkü mevcut olana güvenemez. Ayrıca başka bir kütüphanenin Promise'ini de gerçekten tüketemezsiniz. Beklediğiniz şekilde davranacağına güvenemezsiniz
Bu bir tahmin değil; yıllarca gerçekten böyleydi ve birçok insanın katlanmak zorunda kaldığı bir cehennemdi
Belirsiz sezgime göre signals, genelleştirilmiş
useEffect()e fazla benziyor; React'e girerse render döngüsü sırasında ne olup bittiğini daha da kafa karıştırıcı hale getirebilir. İyi ya da kötü, React signals'tan farklı bir güncelleme yaklaşımı seçti. Yine de uygulanabilirliği konusunda yanılıyor olabilirimuseEffectimperatif davranışı temiz biçimde izole ederBu, Ember veri bağlamasına çok benziyor ve sonunda imperatif bir kâbusa dönüşebilir. Varsayılan durum “ayağına sıkmaya hazır bir silah”a yakın; öyle olmamasını sağlamak için muazzam bir bilişsel yük ve meta pattern'ler gerekir
https://nodejs.org/en/learn/asynchronous-work/the-nodejs-eve...
Bağlantı verilen README’deki örneği anlayamadım
// A library or framework defines effects based on other Signal primitivesdeclare function effect(cb: () => void): (() => void);Hangi kütüphane? Hangi framework? Burada koptum.
effectnedir?effect(() => element.innerText = parity.get());effect, parity her değiştiğinde bu lambda’yı çağırması gerektiğini nasıl biliyor? Signal her değiştiğinde bu lambda’yı mı çağırıyor? Öyleyse önbelleğe alma konusundan neden bahsediliyor? Muhtemelen öyle değildirHer hâlükârda yazarların aktarmaya çalıştığı şeyi doğru anladıysam signal fikrinin kendisi mantıklı görünüyor. Ancak bu tür bir ayrık mimarinin büyük sorunu, uygulama yeterince karmaşık hâle geldiğinde belirli bir olayın neden gerçekleştiğini izlerken yolunuzu kaybetmeniz. İdeal olarak signals stack trace’i düzelterek, callback çağrıldığında en başta signal’ı tetikleyen kodun stack trace’ini zaten içermeli
effectadlı fonksiyonu dışa aktaran birden fazla kütüphane var ve signal güncellemelerine tepki olarak rastgele kod çalıştırmayı sağlıyorlar. Preact dokümanlarındaki signals ve effects’e giriş iyi: https://preactjs.com/guide/v10/signals#effectfnAnladığım kadarıyla bu tür bir effect fonksiyonu önce callback’i bir kez çalıştırarak çalışma sırasında hangi signal’lara erişildiğini kontrol ediyor ve o callback’in bağımlı olduğu signal her güncellendiğinde callback’i yeniden çağırıyor. Signal erişimi senkron ve tek iş parçacıklıysa, callback çalışırken bir signal’a erişilmiş olması, o callback’in ilgili signal’a abone olması gerektiğini bilmek için yeterli
Getter ile de yapılabilir. effect fonksiyonunun, getter metodunda signal’ın hangi özelliğine erişildiğini izlediği bir yöntem; bildiğim kadarıyla Vue 2 geçmişte bunu kullanıyordu. Proxy ile nesne erişimi de izlenebilir. Önerideki örnekte signal değerine erişmek için çağrılan bir
getmetodu var ve bu metodun çalıştırılması yoluyla bağımlılıklar izlenebilir[1] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
[2] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
parity.get()çağrısı,effect()’e geçirilen fonksiyon için bir bağımlılık kaydeder.paritygüncellendiğinde o fonksiyon çağrılırSignal her değiştiğinde değil, yalnızca bağımlı olduğu signal değiştiğinde çağrılır
Bu durumda
parity,isEven’e bağımlıdır;isEvendecounter’a bağımlıdır. Bu yüzdencountergüncellendiğinde tüm bağımlılık zinciri geçersiz kılınır,paritygeçersiz olur ve callback yeniden çalıştırılıreffectgibi izleme bağlamlarında, okuma signal’ın durum düğümü ile effect’in hesaplama düğümü arasında bir kenar oluşturur; bu da pratikte ikincisinin, birincideki sonraki yazmalara abone olmasını sağlayarak hesaplamanın ne zaman yeniden çalıştırılacağını belirlereffect, çağırmak istediğiniz rastgele bir fonksiyondursignals’da bağımlılık izleme mekanizması hangi değerin yeniden hesaplanması gerektiğini bilir; bunun sonucunda sistem hangi fonksiyonun yeniden çağrılması gerektiğini de bilir
effectimplementasyonu için gerekli olacağını düşünüyorumBununla ilgili olarak S.js var: https://github.com/adamhaile/s
signals’ı seviyorum. UI oluştururken diğer tüm temel öğelere tercih ederim; belki tek istisna cassowary kısıt algoritması olabilir. Eğlence için kullandığım her dilde signals’ı taklit etmeye çalışıyorum
Ama bunun JavaScript dilinin kendisine girecek bir şey olduğunu hiç düşünmüyorum. Dilin bir süre rahat bırakılmasını isterim. İnsanlar zaten takip etmekte zorlanıyor ve TC-39 insanları şimdiden dilden ürkütüp uzaklaştırıyor
Bu, en sevdiğim JS effect sistemi olan MobX’e çok benziyor
MobX sürümü şöyle
import { observable, computed, autorun } from 'mobx';const counter = observable.box(0);const isEven = computed(() => (counter.get() & 1) === 0);const parity = computed(() => isEven.get() ? "even" : "odd");autorun(() => { element.innerText = parity.get(); });setInterval(() => counter.set(counter.get() + 1), 1000);“Şu sıralar kullandığım framework’ü standart kütüphaneye gömelim!” havasında
Kız arkadaşının adını vücuduna dövme yaptırmaya benziyor
Çoğu framework’ün kullanmak üzere yakınsadığı yapı taşını standart kütüphaneye koymak
Promises da yaygın biçimde kullanıldıktan sonra standart kütüphaneye girdi; bu da ona benziyor