paint-brush
JavaScript ile Geliştirilmiş Formlarda Yinelenen Getirme İsteklerinin Nasıl İptal Edileceğine İlişkin Kılavuzile@austingil
2,570 okumalar
2,570 okumalar

JavaScript ile Geliştirilmiş Formlarda Yinelenen Getirme İsteklerinin Nasıl İptal Edileceğine İlişkin Kılavuz

ile Austin Gil8m2023/02/10
Read on Terminal Reader
Read this story w/o Javascript

Çok uzun; Okumak

Yanlışlıkla bir yinelenen istek/yarış koşulu hatasına neden olmuş olma ihtimaliniz yüksektir. Bugün size bu sorunu anlatacağım ve bundan kaçınmak için önerilerimi anlatacağım. Buradaki temel sorun 'event.preventDefault()'dur. Bu yöntem, tarayıcının yeni sayfayı yükleme ve formu gönderme gibi varsayılan davranışı gerçekleştirmesini engeller.
featured image - JavaScript ile Geliştirilmiş Formlarda Yinelenen Getirme İsteklerinin Nasıl İptal Edileceğine İlişkin Kılavuz
Austin Gil HackerNoon profile picture

Bir form gönderimini geliştirmek için JavaScript fetch API'sini kullandıysanız, yanlışlıkla yinelenen istek/yarış koşulu hatasına neden olma ihtimaliniz yüksektir. Bugün size bu sorunu anlatacağım ve bundan kaçınmak için önerilerimi anlatacağım.


(İsterseniz video sonunda)


Çok temel bir konuyu ele alalım HTML formu tek bir giriş ve gönder düğmesiyle.


 <form method="post"> <label for="name">Name</label> <input id="name" name="name" /> <button>Submit</button> </form> 


Gönder butonuna bastığımızda tarayıcı tüm sayfayı yenileyecektir.


Gönder düğmesine tıklandıktan sonra tarayıcının nasıl yeniden yüklendiğine dikkat edin.


Sayfa yenileme her zaman kullanıcılarımıza sunmak istediğimiz deneyim değildir; bu nedenle yaygın bir alternatif, sayfa yenilemeyi kullanmaktır. JavaScript formun "gönder" olayına bir olay dinleyicisi eklemek, varsayılan davranışı önlemek ve form verilerini fetch API'sini kullanarak göndermek için.


Basit bir yaklaşım aşağıdaki örneğe benzeyebilir.


Sayfa (veya bileşen) bağlandıktan sonra form DOM düğümünü alırız, formu kullanarak bir fetch isteği oluşturan bir olay dinleyicisi ekleriz aksiyon , yöntem , Ve veri ve işleyicinin sonunda olayın preventDefault() yöntemini çağırırız.


 const form = document.querySelector('form'); form.addEventListener('submit', handleSubmit); function handleSubmit(event) { const form = event.currentTarget; fetch(form.action, { method: form.method, body: new FormData(form) }); event.preventDefault(); }


Şimdi, herhangi bir JavaScript etkin noktası bana GET ve POST hakkında tweet atmaya başlamadan ve gövde metnini talep etmeden önce İçerik türü ve başka ne olursa olsun, şunu söyleyeyim, biliyorum. fetch isteğini kasıtlı olarak basit tutuyorum çünkü asıl odak nokta bu değil.


Buradaki en önemli konu event.preventDefault() dur. Bu yöntem, tarayıcının yeni sayfayı yükleme ve formu gönderme gibi varsayılan davranışı gerçekleştirmesini engeller.


Şimdi ekrana bakıp gönder tuşuna basarsak sayfanın yeniden yüklenmediğini görebiliriz ancak ağ sekmemizde HTTP isteğini görürüz.


Tarayıcının tam sayfayı yeniden yüklemediğine dikkat edin.


Ne yazık ki, varsayılan davranışı önlemek için JavaScript kullanarak, aslında varsayılan tarayıcı davranışında olmayan bir hata ortaya çıkardık.


Düz kullandığımızda HTML ve gönder düğmesine birkaç kez hızlı bir şekilde basarsanız, en sonuncusu dışındaki tüm ağ isteklerinin kırmızıya döndüğünü fark edeceksiniz. Bu, bunların iptal edildiğini ve yalnızca en son isteğin yerine getirildiğini gösterir.


Bunu JavaScript örneğiyle karşılaştırırsak tüm isteklerin gönderildiğini ve hiçbirinin iptal edilmeden tamamlandığını görürüz.


Bu bir sorun olabilir, çünkü her istek farklı süre alsa da başlatıldıklarından farklı bir sırayla çözümlenebilir. Bu, bu isteklerin çözümüne işlevsellik eklersek bazı beklenmedik davranışlarla karşılaşabileceğimiz anlamına gelir.


Örnek olarak, her istek için artacak bir değişken (" totalRequestCount ") oluşturabiliriz. handleSubmit fonksiyonunu her çalıştırdığımızda, mevcut isteği takip etmek için toplam sayıyı artırmanın yanı sıra mevcut sayıyı da yakalayabiliriz (“ thisRequestNumber ”).


Bir fetch isteği çözümlendiğinde, ona karşılık gelen numarayı konsola kaydedebiliriz.


 const form = document.querySelector('form'); form.addEventListener('submit', handleSubmit); let totalRequestCount = 0 function handleSubmit(event) { totalRequestCount += 1 const thisRequestNumber = totalRequestCount const form = event.currentTarget; fetch(form.action, { method: form.method, body: new FormData(form) }).then(() => { console.log(thisRequestNumber) }) event.preventDefault(); }


Şimdi, gönder düğmesini birkaç kez kırarsak, konsola farklı sayıların sırasız şekilde yazdırıldığını görebiliriz: 2, 3, 1, 4, 5. Bu ağ hızına bağlıdır, ancak sanırım hepimiz aynı fikirdeyiz. bu ideal değil.


Bir kullanıcının arka arkaya birkaç fetch isteği tetiklediği ve bu istek tamamlandıktan sonra uygulamanızın sayfayı değişikliklerle güncellediği bir senaryo düşünün. Kullanıcı, isteklerin sıra dışı bir şekilde çözülmesi nedeniyle sonuçta hatalı bilgiler görebilir.


Tarayıcı önceki istekleri iptal ettiğinden ve en son istek tamamlandıktan sonra sayfayı yükleyerek en güncel sürümü yüklediğinden, bu, JavaScript olmayan dünyada bir sorun değildir. Ancak sayfa yenilemeleri o kadar da seksi değil.


JavaScript severler için iyi haber şu ki, her ikisine de sahip olabiliyoruz seksi kullanıcı deneyimi VE tutarlı bir kullanıcı arayüzü!


Sadece biraz daha ayak işi yapmamız gerekiyor.


fetch API belgelerine bakarsanız, AbortController ve fetch seçeneklerinin signal özelliğini kullanarak bir getirme işlemini iptal etmenin mümkün olduğunu göreceksiniz. Şunun gibi bir şeye benziyor:


 const controller = new AbortController(); fetch(url, { signal: controller.signal });


fetch isteğine AbortContoller sinyalini sağlayarak, AbortContoller abort yöntemi tetiklendiğinde isteği iptal edebiliriz.


JavaScript konsolunda daha net bir örnek görebilirsiniz. Bir AbortController oluşturmayı, fetch isteğini başlatmayı ve ardından hemen abort yöntemini çalıştırmayı deneyin.


 const controller = new AbortController(); fetch('', { signal: controller.signal }); controller.abort()


Hemen konsola yazdırılan bir istisna görmelisiniz. Chromium tarayıcılarında "Yakalanmadı (sözde) DOMException: Kullanıcı bir isteği iptal etti." yazmalıdır. Ağ sekmesini incelerseniz, Durum Metni "(iptal edildi)" ile başarısız bir istek görmelisiniz.


Chrome geliştirme araçları, JavaScript konsolu açıkken ağa açıldı. Konsolda "const denetleyici = new AbortController();fetch('', { signal: Controller.signal });controller.abort()" kodu bulunur ve ardından "Yakalanmamış (sözde) DOMException: The kullanıcı bir isteği iptal etti." Ağda, "(iptal edildi)" durum metniyle birlikte "localhost"a bir istek var

Bunu aklımızda tutarak, formumuzu gönderme işleyicisine bir AbortController ekleyebiliriz. Mantık şu şekilde olacaktır:


  • Öncelikle önceki istekler için AbortController kontrol edin. Eğer varsa, iptal edin.


  • Daha sonra, mevcut istek için sonraki isteklerde iptal edilebilecek bir AbortController oluşturun.


  • Son olarak, bir istek çözümlendiğinde ilgili AbortController öğesini kaldırın.


Bunu yapmanın birkaç yolu var, ancak gönderilen her <form> DOM düğümü ile ilgili AbortController arasındaki ilişkileri depolamak için bir WeakMap kullanacağım. Bir form gönderildiğinde WeakMap buna göre kontrol edip güncelleyebiliriz.


 const pendingForms = new WeakMap(); function handleSubmit(event) { const form = event.currentTarget; const previousController = pendingForms.get(form); if (previousController) { previousController.abort(); } const controller = new AbortController(); pendingForms.set(form, controller); fetch(form.action, { method: form.method, body: new FormData(form), signal: controller.signal, }).then(() => { pendingForms.delete(form); }); event.preventDefault(); } const forms = document.querySelectorAll('form'); for (const form of forms) { form.addEventListener('submit', handleSubmit); }


Önemli olan, bir iptal denetleyicisini karşılık gelen formuyla ilişkilendirebilmektir. Formun DOM düğümünü WeakMap anahtarı olarak kullanmak bunu yapmanın kolay bir yoludur.


Bunu yerine getirdiğimizde, fetch isteğine AbortController sinyalini ekleyebilir, önceki denetleyicileri iptal edebilir, yenilerini ekleyebilir ve tamamlandığında bunları silebiliriz.


Umarım bunların hepsi mantıklıdır.


Şimdi o formun gönder butonunu defalarca kırarsak, en sonuncusu dışındaki tüm API isteklerinin iptal edildiğini görebiliriz.


Bu, bu HTTP yanıtına yanıt veren herhangi bir işlevin beklediğiniz gibi davranacağı anlamına gelir.


Şimdi, yukarıda sahip olduğumuz aynı sayma ve kayıt mantığını kullanırsak, gönder düğmesini yedi kez kırabiliriz ve konsolda altı istisna ( AbortController nedeniyle) ve bir "7" günlüğü görürüz.


Tekrar gönderirsek ve isteğin çözülmesi için yeterli süre tanırsak konsolda "8" rakamını görürüz. Ve gönder düğmesine birkaç kez basarsak, istisnaları ve son istek sayısını doğru sırayla görmeye devam edeceğiz.


Bir istek iptal edildiğinde konsolda DOMExceptions'ın görünmesini önlemek için biraz daha mantık eklemek istiyorsanız, fetch isteğinizin arkasına bir .catch() bloğu ekleyebilir ve hatanın adının “ AbortError “ ile eşleşip eşleşmediğini kontrol edebilirsiniz:


 fetch(url, { signal: controller.signal, }).catch((error) => { // If the request was aborted, do nothing if (error.name === 'AbortError') return; // Otherwise, handle the error here or throw it back to the console throw error });

Kapanış

Bu yazının tamamı JavaScript ile geliştirilmiş formlara odaklandı, ancak bir fetch isteği oluşturduğunuzda AbortController eklemek muhtemelen iyi bir fikirdir. Zaten API'ye yerleşik olmaması gerçekten çok kötü. Ancak umarım bu size onu dahil etmek için iyi bir yöntem gösterir.


Ayrıca bu yaklaşımın kullanıcının gönder düğmesine defalarca spam göndermesini engellemediğini de belirtmekte fayda var. Düğme hâlâ tıklanabilir durumda ve istek hâlâ etkinleşiyor; yalnızca yanıtlarla ilgilenmek için daha tutarlı bir yol sağlıyor.


Ne yazık ki, bir kullanıcı gönder düğmesini spam olarak gönderirse , bu istekler yine de arka ucunuza gider ve bir sürü gereksiz kaynağın tüketilmesine neden olabilir.


Bazı saf çözümler, bir gönder düğmesini kullanarak gönder düğmesini devre dışı bırakmak olabilir. geri dönmek veya yalnızca önceki istekler çözüldükten sonra yeni istekler oluşturmak. Bu seçenekleri sevmiyorum çünkü kullanıcının deneyimini yavaşlatmaya dayanıyorlar ve yalnızca istemci tarafında çalışıyorlar.


Komut dosyasıyla yazılmış istekler yoluyla kötüye kullanımı gidermezler.


Sunucunuza gelen çok fazla istekten kaynaklanan kötüye kullanımı gidermek için muhtemelen bazı ayarlar yapmak isteyebilirsiniz. hız sınırlaması . Bu yazının kapsamını aşıyor ama belirtmekte fayda var.


Hız sınırlamanın, yinelenen istekler, yarış koşulları ve tutarsız kullanıcı arayüzü güncellemeleri gibi orijinal sorunları çözmediğini de belirtmekte fayda var. İdeal olarak, her iki ucu da kaplamak için her ikisini de kullanmalıyız.


Her neyse, bugünlük söyleyeceklerim bu kadar. Aynı konuyu kapsayan bir video izlemek istiyorsanız bunu izleyin.

Okuduğunuz için çok teşekkür ederim. Bu makaleyi beğendiyseniz lütfen Paylaş . Beni desteklemenin en iyi yollarından biri bu. Ayrıca bültenime kaydol veya beni Twitter'da takip et Yeni makalelerin ne zaman yayınlanacağını bilmek istiyorsanız.


İlk olarak şu tarihte yayınlandı: austingil.com .