A weather-powered interface has two separate jobs: load its document and obtain enough external data to give a useful answer. Treating both as one loading state makes it difficult to explain why a page feels slow.

The concrete example here is the What to wear today page on my What To Wear Atlas site. Its output combines temperature bands with explicit adjustments for wind, rain, comfort and plans. That rule-based output makes a manual temperature path possible even when weather requests fail.

Start by defining a useful fallback

A user can enter a temperature instead of waiting for a location lookup and forecast. This should be a real mode with clear provenance: a manually entered temperature does not imply a current wind or rain forecast. The editorial temperature guide also remains useful without the interactive tool. This separates the underlying answer from the availability of an external service.

Parallel work after a necessary dependency

The deployed JavaScript first resolves the weather grid. It then requests period and hourly forecasts concurrently using Promise.allSettled. An update callback can expose usable results while the other request is still pending. The source ranks usable hourly data above period-only data.

The important design choice is not simply “use promises.” It is to identify the dependency that must finish first, then avoid placing independent requests in a sequence. Promise.allSettled also allows the application to inspect partial failures rather than rejecting the combined operation at the first rejected promise.

An aborted request needs an interface consequence

The deployed request helper uses AbortController, a timeout and an external cancellation signal. Cancelling a request is only part of the job. The interface needs to release its busy state, explain the failure and keep a useful next action available. For this page, the manual temperature path is an appropriate alternative. A new selection must also prevent an older response from replacing a newer result.

Images have the same race problem

The deployed image helper calls image.decode() before revealing a changed outfit image. A WeakMap tracks the image request signature; a completed decode only reveals the image if its signature still matches. That avoids showing an obsolete image after a rapid input change. Error handling also matters: a broken illustration should not remove the text explanation of the outfit.

Caching requires an explicit freshness policy

The public bundle contains a versioned browser cache with timestamp checks and bounded storage. A cache can reduce repeat work, but a forecast response needs a freshness policy and a visible source time. A cached value should never silently masquerade as a new observation. Storage can also be unavailable, so cache access must be allowed to fail without preventing the core tool from working.

What I would measure before claiming an improvement

This article does not include a before/after benchmark. The presence of concurrent requests, caching or decoding guards does not establish a measured speed gain.

A useful test plan separates document loading from time to a usable outfit. Record navigation start, first meaningful content, location resolution, first usable forecast, and final outfit display. Test a fresh cache and a warm cache separately. Keep the device and network conditions consistent across versions. Report repeated runs, the sample size and the spread, rather than choosing the fastest run.

Also test failure behavior: reject the hourly endpoint, delay one forecast branch, deny location access, disable browser storage and switch inputs quickly. Those checks answer a different question from a Lighthouse score: can the person still finish the task?

The general lesson is to give each asynchronous dependency a deadline, a partial-success policy and a user-visible fallback. That creates a page whose usefulness does not depend on every request finishing successfully.

Disclosure: AI assisted with drafting and editing this article. Implementation descriptions are based on inspection of the deployed page and its public JavaScript. No measured performance improvement is claimed.