The decision
An asynchronous operation has at least three visible states: pending, completed, and failed. A button that starts a request should explain which state applies. Keep the user’s input until completion is confirmed. A rejected promise should lead to an actionable message, while diagnostic details stay on the server.
A worked example
A draft-writing form sends a note to an API. The API may time out after the model accepted the work. Clearing the note immediately destroys the only copy. Keep the note in local component state, disable duplicate submissions while the request is pending, and show a retry option that preserves the input. If work continues on the server, return a job ID so the browser can ask about the same operation.
How to put it into practice
- Use try/catch around awaited work and finally for cleanup that must happen in both outcomes.
- Distinguish network failure from a successful HTTP response that reports an application error.
- Do not use one global loading flag for unrelated operations. Tie state to the current operation or job.
- Decide whether retry starts new work or checks existing work. Expensive operations need a stable request identifier.
async function submitDraft(note) {
const response = await fetch("/api/draft", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ note })
});
if (!response.ok) throw new Error("Draft unavailable. Try again.");
return response.json();
}A failure to plan for
Retrying a payment or model call blindly can duplicate side effects. A disabled button helps the interface but does not protect the server from retries, multiple tabs, or two workers.
Try it on your project
Simulate a delayed success, an HTTP 503, and a connection failure. In each case verify that the button becomes usable again, the input remains available, and the displayed message does not expose provider keys or internal exception text.
Primary reference
Keep the next step small
Use the free demand scorecard or planning tools to make your assumptions explicit. The $19 launch kit brings the blueprint and seven editable worksheets together.