event.preventDefault() ifadesini ilk await ifadesinden önce çağırın, eşzamansız doğrulamanızı çalıştırın, ardından yeni bir gönderim denemesi başlatmak için form.requestSubmit() kullanın. Tek kullanımlık bir koruma, bu ikinci denemenin eşzamansız kontrolü yinelemeden devam etmesini sağlar.
Bu eğitim, Mac’te küçük bir tarayıcı arayüzünü düzenleyenler içindir. Bir formun, sentetik bir etiket kontrolü başarılı olduktan sonra iletişim kutusunu kapattığı yerel bir HTML örneği oluşturacaksınız. Aynı olay işleme kalıbı, sayfaya giden veya istek gönderen sıradan formlar için de geçerlidir.
Eşzamansız bir gönderim işleyicisi gönderimi neden geciktirmez?
Tarayıcı, bir olay dinleyicisinin döndürdüğü promise’i beklemez. DOM olay dağıtım algoritması dinleyicileri çağırır ve devam eder; HTML gönderim algoritması ilerlemeden önce submit olayının iptal edilip edilmediğini kontrol eder. Dinleyiciye async eklemek, bu yaşam döngüsüne bir bekleme adımı eklemez. DOM Standardı: olay dağıtımı, HTML Standardı: form gönderim algoritması
Eşzamansız bir işlev ilk await ifadesine kadar eşzamanlı çalışır, sonra eşzamansız olarak devam eder. Bu nedenle, beklenen promise zaten yerine getirilmiş olsa bile iptal işlemi ilk await ifadesinden önce yapılmalıdır. Sonrasında preventDefault() çağırmak, tarayıcının zaten verdiği gönderim kararını geri alamaz. MDN: async işlevi
İptal, özgün denemeyi sona erdirir; daha sonra devam ettirilmek üzere askıya almaz. Doğrulama başarılı olduktan sonra kodunuz açıkça yeni bir gönderim isteğinde bulunmalıdır. Ayrıca preventDefault() olay yayılımını sürdürür, dolayısıyla diğer dinleyiciler de olayı görebilir. MDN: Event.preventDefault()
Formun submit olayını dinleyin. Böylece bir düğmeyle yapılan gönderimler, Enter tuşuna basma gibi desteklenen örtük gönderimler ve requestSubmit() çağrıları kapsanır. Yalnızca düğme tıklamasını işleyen bir işleyici, tüm giriş yollarını kapsamaz. Yerel kısıt doğrulaması normalde önce çalışır: zorunlu bir alan geçersizse gönderim engellenir ve submit olayı tetiklenmez. MDN: HTMLFormElement submit olayı
Formun gönderim davranışını hangi yöntem korur?
Başarılı kontrolün normal form yaşam döngüsüne dönmesini istiyorsanız requestSubmit() kullanın. Doğrudan submit() çağırmak hem kısıt doğrulamasını hem de submit olayını atlar. Bu kestirme yol, eşzamansız işleyicinizin koruması gereken sözleşmeyi değiştirir. MDN: HTMLFormElement.submit()
| Yaklaşım | Ne olur | Buraya uygunluğu |
|---|---|---|
| Dinleyiciden bir promise döndürmek | Olay dağıtımı promise’i beklemeden devam eder | Varsayılan işlemi geciktirmez |
İptal edip submit() çağırmak |
Gönderim yerel doğrulamayı ve gönderim dinleyicilerini atlar | Yaşam döngüsünü değiştirir |
İptal edip requestSubmit(submitter) çağırmak |
Yerel doğrulama ve gönderim olayı yeniden çalışır | Amaçlanan gönderim yolunu korur |
Beklemeden önce event.submitter değerini alın. Bu düğmeyi requestSubmit() metoduna iletmek, gönderim geçersiz kılmaları ve varsa ad/değer katkısı da dahil olmak üzere rolünü korur. Gönderici yoksa requestSubmit() metodunu bağımsız değişken olmadan çağırın. Sağlanan bir düğme yine de forma ait olmalıdır; geçersiz bir düğme veya başka bir forma ait düğme hata oluşturur. MDN: HTMLFormElement.requestSubmit()
Yeni gönderim, dinleyicinizi yeniden tetikler. Bu nedenle aşağıdaki örnek iki ayrı durum değişkeni kullanır: pending eşzamanlı eşzamansız kontrolleri önlerken allowNextSubmit işleyiciden tam olarak bir kez eşzamanlı geçiş yapılmasına izin verir. Kalıcı bir “doğrulandı” bayrağı fazla kapsamlı olurdu; sonraki düzenlemeler önceki bir sonucu yeniden kullanabilirdi.
Mac’inizde eksiksiz bir yerel örnek oluşturun
Aşağıdaki eksiksiz belgeyi düz metin düzenleyicisinde async-form.html adıyla kaydedin, ardından Mac’inizde güncel bir tarayıcıda açın. Kitaplık, içe aktarma, sunucu veya kurulum gerekmez. Standart, Safari 16 ve sonrasında requestSubmit() desteğini listeler. HTML Standardı: form API’leri
Örnek, varsayılan işlemi yerel olarak kolayca görebilmek için method="dialog" kullanır. Başarılı gönderim, çevreleyen iletişim kutusunu kapatır ve returnValue değerini gönderim düğmesinden alır; form denetimlerini göndermez. Açma düğmesi, iletişim kutusunu görüntülemek için showModal() çağırır. MDN: dialog öğesi, MDN: HTMLDialogElement.showModal()
Doğrulayıcı kasıtlı olarak sentetiktir: kısa bir zamanlayıcıdan sonra, boşlukları kaldırıldığında en az üç karakter içeren etiketleri kabul eder, tam olarak küçük harflerle taken olan etiketi reddeder ve tam olarak küçük harflerle error olan etiket için hata fırlatır. Gecikme, eşzamansız tamamlanmayı gösterir; bir performans ölçümü değildir.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Asynchronous form validation</title>
</head>
<body>
<h1>Label preview</h1>
<button id="open" type="button">Open form</button>
<p id="outcome" role="status"></p>
<dialog id="editor" aria-labelledby="dialog-title">
<form id="label-form" method="dialog">
<h2 id="dialog-title">Choose a label</h2>
<label for="label">Label</label>
<input id="label" name="label" required autofocus>
<button type="submit" value="accepted">Continue</button>
<button id="cancel" type="button">Cancel</button>
<p id="status" role="status"></p>
</form>
</dialog>
<script>
const dialog = document.getElementById("editor");
const form = document.getElementById("label-form");
const input = document.getElementById("label");
const status = document.getElementById("status");
const outcome = document.getElementById("outcome");
const openButton = document.getElementById("open");
const cancelButton = document.getElementById("cancel");
let pending = false;
let allowNextSubmit = false;
let revision = 0;
async function validateLabel(value) {
await new Promise(resolve => setTimeout(resolve, 700));
const label = value.trim();
if (label === "error") {
throw new Error("Synthetic validation failure");
}
return label.length >= 3 && label !== "taken";
}
openButton.addEventListener("click", () => {
revision += 1;
dialog.returnValue = "";
status.textContent = "";
outcome.textContent = "";
dialog.showModal();
});
input.addEventListener("input", () => {
revision += 1;
});
cancelButton.addEventListener("click", () => dialog.close());
dialog.addEventListener("close", () => {
revision += 1;
outcome.textContent = "Dialog closed. Return value: " +
(dialog.returnValue || "(empty)");
});
form.addEventListener("submit", async event => {
if (allowNextSubmit) {
allowNextSubmit = false;
return;
}
event.preventDefault();
if (pending) return;
pending = true;
const submitter = event.submitter;
const value = input.value;
const checkedRevision = revision;
status.textContent = "Checking label...";
try {
const valid = await validateLabel(value);
if (!dialog.open) return;
if (revision !== checkedRevision || input.value !== value) {
status.textContent = "The label changed. Submit again.";
return;
}
if (!valid) {
status.textContent =
"Use at least three characters and avoid taken.";
return;
}
status.textContent = "Check passed. Submission requested.";
allowNextSubmit = true;
try {
if (submitter) form.requestSubmit(submitter);
else form.requestSubmit();
} finally {
allowNextSubmit = false;
}
} catch (error) {
if (dialog.open && revision === checkedRevision) {
status.textContent = "The check failed. Try again.";
}
console.error(error);
} finally {
pending = false;
}
});
</script>
</body>
</html>
Örneğin tarayıcı davranışı, belgelenmiş yaşam döngüsünden çıkarılmıştır. Küçük bir Node.js EventTarget kontrolü zamanlama farkını doğruladı: eşzamanlı iptal, dağıtım sonucunu değiştirdi; await sonrasındaki iptal ise bu sonucu etkilemekte geç kaldı. Eksiksiz iletişim kutusu örneği burada bir Mac tarayıcısında çalıştırılmadı.
Koruma sıralamayı nasıl korur ve değişiklikleri nasıl ele alır?
İlk gönderimde işleyici hemen iptal eder ve hem etiketi hem de gönderimi başlatan düğmeyi kaydeder. Kontrol beklemedeyken başka bir gönderim olayı da iptal edilir, ancak yeni bir doğrulama başlatılmaz. Böylece hızlı ve tekrarlanan gönderimler, kontrollerin çakışmasına yol açmaz.
Kontrol tamamlandığında işleyici, iletişim kutusunun hâlâ açık olduğunu ve etiketin değişmediğini doğrular. Revizyon sayacı, kullanıcı metni değiştirip sonra eski hâline döndürse bile düzenlemeyi algılar. Değer karşılaştırması da alan içindeki metin farklı kalacak şekilde doğrudan yapılan değer değişikliklerini yakalar.
Başarılı bir sonuç, requestSubmit() çağrısından hemen önce allowNextSubmit değerini ayarlar. Bu yöntem yerel doğrulama ve gönderim olayı yolunu yeniden çalıştırır. Dinleyici yeniden çağrıldığında izni kullanır ve iptal etmeden döner. Böylece tarayıcı, iletişim kutusunu kapatan varsayılan işlemi gerçekleştirebilir. Bu sıralama, standardın gönderim olayından önce doğrulama yapılması sırasına uyar. HTML Standardı: form gönderim algoritması
İçteki finally, hiçbir gönderim olayı gerçekleşmese veya yöntem hata fırlatsa bile izni temizler. Dıştaki finally ise ret, hata, güncelliğini yitirmiş sonuç veya başarılı yeniden denemeden sonra pending değerini temizler. Böylece başarısız bir denemeden sonra form başka bir kontrol için kullanılabilir kalır.
İletişim kutusunun kapatılması da revizyonu artırır. Daha önceki bir açılıştan kalan sonuç, sonraki bir açılışa izin veremez. Bu bağımsız belgede bu kontroller, kullanılabilir etkileşim yollarını kapsar. Daha fazla alan veya bu alanları güncelleyen betikler eklerseniz, anlık görüntü ve revizyon işleme mantığını doğrulayıcının bağlı olduğu her değeri kapsayacak şekilde genişletin.
Başarı, ret ve kesinti yollarını sınayın
Bu kontrolleri yerel tarayıcı örneğinde çalıştırın. Beklenen sonuçlar sağlanan koddan çıkarılmıştır; tarayıcıda test edildikleri iddia edilmemektedir.
| İşlem | Beklenen sonuç |
|---|---|
Etiketi boş bırakıp Devam seçeneğini seçin |
Yerel zorunlu alan doğrulaması, eşzamansız işleyici çalışmadan gönderimi engeller |
ab girip Devam seçeneğini seçin |
Kontrolün ardından iletişim kutusu açık kalır ve ret mesajı görüntülenir |
taken girin |
Sentetik kural bunu reddeder |
sample girin |
Kontrol sırasında iletişim kutusu açık kalır, ardından accepted dönüş değeriyle kapanır |
error girin |
Hata mesajı görünür ve yeniden gönderim yapmak mümkün olur |
| Bir etiket gönderip kontrol sırasında düzenleyin | Sonuç atılır ve form yeniden gönderim ister |
| Kontrol sırasında tekrar tekrar gönderin | Yalnızca ilk deneme eşzamansız kontrol başlatır |
Kontrol sırasında İptal seçeneğini seçin |
İletişim kutusu, bekleyen sonucu beklemeden kapanır |
Giriş odağındayken Enter tuşuyla göndermeyi de deneyin. Örtük gönderim, form yapısına ve platform kurallarına bağlıdır; submit olayını ele almanın nedeni, desteklenen hangi etkileşim form gönderimini tetiklerse onu kapsamaktır. MDN: HTMLFormElement submit olayı
Form normal bir istek gönderdiğinde neler değişir?
İstek gönderen mevcut bir form için gerçek action, method, alan adlarını, düğme değerlerini ve gönderim geçersiz kılmalarını koruyun. Sentetik doğrulayıcıyı gerçek eşzamansız kontrolünüzle değiştirin. İletişim kutusunu açma ve kapatma kodu bu gösterime özeldir; iptal–doğrula–istekte bulun sırası formun gönderim işleyicisinde yer alır.
Alanları son gönderim için kullanılabilir durumda tutun. Bekleme boyunca denetimleri devre dışı bırakmak dikkat gerektirir: tarayıcı gönderim giriş listesini oluştururken devre dışı alanları dışarıda bırakır. Örnek bunun yerine düzenlemeye izin verir ve güncelliğini yitirmiş doğrulama sonuçlarını reddeder. HTML Standardı: giriş listesini oluşturma
Başka gönderim dinleyicileri varsa hem iptal edilen ilk denemeyi hem de sonraki denemeyi görürler. Aynı işi iki kez yapmamaları veya izin verilen geçiş sırasında doğrulanan değerleri değiştirmemeleri için bu dinleyicileri koordine edin. requestSubmit() tamamlanmayı da garanti etmez: başka bir dinleyici bunu iptal edebilir ve yerel kısıtlar bunu engelleyebilir. Dönüş değeri bir tamamlama promise’i değil, undefined olur. MDN: HTMLFormElement.requestSubmit()
Temel sözleşme nettir: eşzamanlı olarak iptal edin, tanımlanmış bir değer kümesini doğrulayın, geçersiz sonuçları atın ve yeni bir yerel gönderim denemesine bir kez izin verin. Böylece eşzamansız doğrulamaya iş akışında açık bir yer sağlarken tarayıcının form yaşam döngüsünü korursunuz.
Kaynaklar
DOM Standardı — WHATWG
HTML Standardı: Form öğesi — WHATWG
async işlevi — MDN Web Docs
Event: preventDefault() metodu — MDN Web Docs
HTMLFormElement: submit olayı — MDN Web Docs
HTMLFormElement: submit() metodu — MDN Web Docs
HTMLFormElement: requestSubmit() metodu — MDN Web Docs
Dialog öğesi — MDN Web Docs
HTMLDialogElement: showModal() metodu — MDN Web Docs