Bir form gönderimini geliştirmek için JavaScript 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. fetch (İsterseniz video sonunda) Çok temel bir konuyu ele alalım tek bir giriş ve gönder düğmesiyle. HTML formu <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. formun "gönder" olayına bir olay dinleyicisi eklemek, varsayılan davranışı önlemek ve form verilerini API'sini kullanarak göndermek için. JavaScript fetch 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 isteği oluşturan bir olay dinleyicisi ekleriz , , Ve ve işleyicinin sonunda olayın yöntemini çağırırız. fetch aksiyon yöntem veri preventDefault() 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 ve başka ne olursa olsun, şunu söyleyeyim, biliyorum. isteğini kasıtlı olarak basit tutuyorum çünkü asıl odak nokta bu değil. İçerik türü fetch Buradaki en önemli konu dur. Bu yöntem, tarayıcının yeni sayfayı yükleme ve formu gönderme gibi varsayılan davranışı gerçekleştirmesini engeller. event.preventDefault() Ş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 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. HTML 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 (" ") oluşturabiliriz. 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 (“ ”). totalRequestCount handleSubmit thisRequestNumber Bir isteği çözümlendiğinde, ona karşılık gelen numarayı konsola kaydedebiliriz. fetch 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ç 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. fetch 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 VE tutarlı bir kullanıcı arayüzü! seksi kullanıcı deneyimi Sadece biraz daha ayak işi yapmamız gerekiyor. API belgelerine bakarsanız, ve seçeneklerinin özelliğini kullanarak bir getirme işlemini iptal etmenin mümkün olduğunu göreceksiniz. Şunun gibi bir şeye benziyor: fetch AbortController fetch signal const controller = new AbortController(); fetch(url, { signal: controller.signal }); isteğine sinyalini sağlayarak, yöntemi tetiklendiğinde isteği iptal edebiliriz. fetch AbortContoller AbortContoller abort JavaScript konsolunda daha net bir örnek görebilirsiniz. Bir oluşturmayı, isteğini başlatmayı ve ardından hemen yöntemini çalıştırmayı deneyin. AbortController fetch abort 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. Bunu aklımızda tutarak, formumuzu gönderme işleyicisine bir ekleyebiliriz. Mantık şu şekilde olacaktır: AbortController Öncelikle önceki istekler için kontrol edin. Eğer varsa, iptal edin. AbortController Daha sonra, mevcut istek için sonraki isteklerde iptal edilebilecek bir oluşturun. AbortController Son olarak, bir istek çözümlendiğinde ilgili öğesini kaldırın. AbortController Bunu yapmanın birkaç yolu var, ancak gönderilen her DOM düğümü ile ilgili arasındaki ilişkileri depolamak için bir kullanacağım. Bir form gönderildiğinde buna göre kontrol edip güncelleyebiliriz. <form> AbortController WeakMap WeakMap 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ü anahtarı olarak kullanmak bunu yapmanın kolay bir yoludur. WeakMap Bunu yerine getirdiğimizde, isteğine sinyalini ekleyebilir, önceki denetleyicileri iptal edebilir, yenilerini ekleyebilir ve tamamlandığında bunları silebiliriz. fetch AbortController 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 ( nedeniyle) ve bir "7" günlüğü görürüz. AbortController 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, isteğinizin arkasına bir bloğu ekleyebilir ve hatanın adının “ “ ile eşleşip eşleşmediğini kontrol edebilirsiniz: fetch .catch() AbortError 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 isteği oluşturduğunuzda 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. fetch AbortController 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 , bu istekler yine de arka ucunuza gider ve bir sürü gereksiz kaynağın tüketilmesine neden olabilir. gönderirse Bazı saf çözümler, bir gönder düğmesini kullanarak gönder düğmesini devre dışı bırakmak olabilir. 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. geri dönmek 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. . Bu yazının kapsamını aşıyor ama belirtmekte fayda var. hız sınırlaması 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. https://www.youtube.com/watch?v=w8ZIoLnh1Dc&embedable=true Okuduğunuz için çok teşekkür ederim. Bu makaleyi beğendiyseniz lütfen . Beni desteklemenin en iyi yollarından biri bu. Ayrıca veya Yeni makalelerin ne zaman yayınlanacağını bilmek istiyorsanız. Paylaş bültenime kaydol beni Twitter'da takip et İlk olarak şu tarihte yayınlandı: austingil.com .