# 透過Websocket提交Form無法抓到資料 ###### tags: `vue` `event loop` `two way binding` `nextTick` `Proxy` `form` ### 需求 是要畫面顯示條碼,要給店家掃描的 店家掃描完,會有websocket來通知我的畫面做表單送出 ### 解決思路 我這邊的作法是寫一個隱藏的form表單, 然後每一個input上面用vue的雙向綁定去綁定我要的資料, 然後給websocket一個callback去執行我表單送出 ### 碰到的問題 從network的payload可以觀察到,我送出的form表單會抓不到我在data上設定的值 #### 具體程式碼 * 這邊有[Codepen](https://codepen.io/hard25670559/pen/XWBNwJg)更詳細的程式碼可以做測試! ```xml <template> <form ref="form" style="display: none;"> <input name="data" v-model="data"/> </form> </template> ``` ```javascript const data = ref(''); const form = ref<HTMLFromElement>(); // 這個是給websocket呼叫的callback function sendForm() { data.value = 'test data'; form.value!.submit(); } ``` ### 目前測試出的可行方法 #### 1. 再設定完資料後,用await nextTick ```javascript async function sendForm() { data.value = 'test data'; await nextTick(); form.value!.submit(); } ``` #### 2. 將data.value = 'test data'用非同步包起來 ```javascript async function sendForm() { await (async () => data.value = 'test data')(); form.value!.submit(); } ``` #### 3. 在設定完資料後,再寫一個Promise ```javascript async function sendForm() { data.value = 'test data'; await new Promise((res, rej) => { res(); }); form.value!.submit(); } ``` ### 困惑的點及猜測 1. 在可行方法中第一點,還相對好理解,反正就是等待vue該tick內的所有程序完成才將表單送出。 2. 在可行方法中的第二點,是我猜測vue3用proxy在做setter,其實是個非同步方法?<br><br>但因為我是使用typescript去寫,編譯器上也沒有提示他是一個非同步方法!<br><br>另外我也不確定proxy的setter是否可以寫成非同步的方法。 3. 在可行方法中的第三點,則是我完全無法理解的方法。<br><br>我是依據我第二點的假設是成立,那麼setter應該是有機率在Promise完成後,setter卻還沒完成,因為setter我並沒有去await他!<br><br>我這邊的猜測是因為Promise的執行時間的長度,可能剛好比vue當中的一個tick的執行時間還長,所以才導致form表單都是有抓到資料的。 4. 該部分我在認知上認為他們兩個是等價的 ### ```javascript function setData(data) { return new Promise((res, rej) => { setTimeout(() => { console.log(data); }, 2000); }); } // 類似sendForm (async () => { setData('data'); const data = await new Promise((res, rej) => { res('test'); }); console.log(data2); // Result: // test // data })(); ``` ```javascript async function sendForm() { data.value = 'test data'; await new Promise((res, rej) => { res(); }); form.value!.submit(); } ``` ### 結論 1. 論點data.value = 'test',屬實是同步操作,而只是透過Proxy的setter去操作 2. 論點Vue所實做的Proxy setter並不是個非同步的方法 3. Proxy setter內會先做Assign value後再去呼叫畫面重新render,而這個部分是屬於Web engine實做,所以我們無法去預期render到底會何時做完 5. 當Assign value後再加一個Promise做等待,或者是將Assign value丟進去Promise內等待,都會讓Form抓的到資料,,是因為當前Queue內沒有其餘的任務,所以才會有這種錯覺產生 * 以下是在Event loop下執行的過程,感謝Hello大大的細心講解 ![](https://i.imgur.com/2NmeXxt.jpg)