jQuery validation 套件支援一個選項參數 submitHandler 可以替換掉原生的 submit() 方法,讓我們自己決定之後要怎麼處理送出的行為(例如可以改成使用 AJAX 來送出資料)。

在我的一個使用案例中,我會去判斷當前的環境,然後根據結果來決定我要用 AJAX 送出資料還是用原生的 submit() 送出。今天因為一些底層架構的修改,使得我判斷當前環境的動作變成是非同步的判斷,因此我就直覺地把我的 handler 改成了 async 函數並且在裡面 await 我的判斷結果,然後再看看怎麼處理。

可是結果程式就爆炸了,不管怎樣表單就是會變成以原生形式送出,根本沒有等到我的 await 執行完,而且我下了中斷點也根本跑不到我 await 之後的下一行。研究了老半天,我才得到一個結論:不可以直接把一個 async 函數傳過去當作 submitHandler,否則就是會這樣。取而代之地,應該先傳入一個同步函數(lambda 函數也可以),然後才是在那個函數裡面呼叫我的 async 函數(且不要傳回),類似下面這樣:

async function handler(form) {
    // 一些非同步的處理
}

$('#form').validate({
    submitHandler: form => { handler(form); }
});

至於為什麼會這樣,我在官方的文件裡面翻來翻去就是沒看到答案,但是我跑去爬了一下 jQuery validation 的原始碼大概就知道是怎麼回事了:原來這個 submitHandler 如果有傳回值的話,是會根據這個傳回值(隱晦轉成 bool)來決定要不要以原生形式送出表單的。而 async 函數會傳回一個 Promise 物件,隱晦轉換就是 true,所以一旦裡面跑到了非同步需要等候的地方,表單馬上就以原生形式送出了,所以我下一行的中斷點自然永遠到不了。取而地之地,只要 submitHandler 沒有傳回值,jQuery validation 就會完全交給我們的 handler 去決定一切。


分享此頁至:
最後修改日期: 2021/06/18

留言

撰寫回覆或留言

發佈留言必須填寫的電子郵件地址不會公開。您的留言可能會在審核之後才出現在頁面上。