---
# System prepended metadata

title: 透過Websocket提交Form無法抓到資料
tags: [event loop, nextTick, two way binding, Proxy, vue, form]

---

# 透過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)