VeeValidate async validators and AbortController: can external cancellation signals abort in-flight field validation?
0 reputation · 30 Jan 2021, 11:21 UTC
0 reputation · 30 Jan 2021, 11:21 UTC
VeeValidate 4+ manages async field validation by awaiting the promise returned from each validator function. When a user types rapidly, successive validate calls overwrite the previous pending promise, but the original asynchronous work continues executing in the background.
The goal is to stop an in-flight validator—such as a debounced API uniqueness check—when the component unmounts or the input value changes again, using the standard AbortController/AbortSignal pattern that fetch and other browser APIs already support. VeeValidate does not currently accept an AbortSignal in its validation pipeline, nor does it expose a cancellation token that the validator can observe.
AbortSignal from the form or field level down to an async validator so that the validator can react to external cancellation?validate call?33275 reputation · 30 Jan 2021, 22:24 UTC
VeeValidate does not provide an AbortSignal to its validation pipeline. When a new validate call is made, the library simply awaits the promise returned by the validator and then discards the result if the value has changed. The original promise continues to run unless the validator itself implements cancellation.
Promise that resolves to null (valid) or a string (error).AbortSignal parameter in the validator signature.AbortError, VeeValidate treats it as a validation failure unless the error is caught and ignored.Because the validator receives only the field value (and an optional field object), it has no way to observe an external cancellation unless you create an AbortController inside the validator or in a surrounding closure. By keeping a reference to the controller you can abort the ongoing request when the component unmounts or when a new validation starts.
Store an AbortController on the field so it survives across validation calls.
const validateUsername = (value, { field }) => {
// Reuse or create a controller on the field
if (!field.__vcController) field.__vcController = new AbortController();
const controller = field.__vcController;
// Abort any previous request
controller.abort();
// Create a fresh controller for this request
const newController = new AbortController();
field.__vcController = newController;
return fetch(`/api/unique?name=${encodeURIComponent(value)}`, {
signal: newController.signal
})
.then(res => res.json())
.then(data => data.isUnique ? null : 'Username taken')
.catch(err => {
if (err.name === 'AbortError') return null; // ignore cancellation
throw err; // propagate other errors
});
};
Abort any pending request when the component unmounts.
import { onUnmounted } from 'vue';
onUnmounted(() => {
if (field.__vcController) field.__vcController.abort();
});
Prevent race conditions: keep a numeric request ID or timestamp that is checked before updating the field state.
let currentRequest = 0;
const validate = async (value, { field }) => {
const requestId = ++currentRequest;
// ... perform fetch with AbortController
return fetch(...)
.then(...)
.then(result => {
if (requestId !== currentRequest) return null; // stale response
return result;
});
};
If you are using a library other than fetch (e.g., Axios, GraphQL client, or a custom promise), let me know so the cancellation strategy can be adapted to that API’s abort support.
| Component | Action | Result |
|---|---|---|
| VeeValidate | Calls validator | Receives Promise |
| Validator | Starts fetch with AbortSignal | In‑flight request |
| AbortController | Abort signal sent | Fetch rejects with AbortError |
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.