Status: backlog Priority: P1 Created: 2026-02-11 Owner: conductor
The primary motivation for the async statechart processor was URL-driven deep state restoration. When a user loads a page with a URL like /users/42/settings/notifications, the routing system must navigate the statechart to the corresponding deeply nested state. Each intermediate state's on-entry may perform async I/O (e.g., loading user data, initializing a settings panel). The async processor (v20150901_async) now supports expressions that return promesa promises, parking the algorithm until they resolve. This spec designs how the routing layer leverages that capability.
apply-external-route (ui_routes.cljc:361-383) finds a state matching the URL path and fires a route-to-* eventroutes (ui_routes.cljc:385-435) creates direct transition elements for every route target, so SCXML's enter-states! handles entering all intermediate statesstart-routing! (ui_routes.cljc:539-559) calls scf/start! which may return a promise with the async processoristate (ui_routes.cljc:240-317) creates route states that invoke co-located statecharts, whose setup may also be asyncstart-routing! calls scf/start! then immediately expects synchronous completion. With the async processor, start! may return a promise.apply-external-route fires a routing event, but does not account for the possibility that the event processing (entering intermediate states) is async.rstate/istate on-entry independently pushes/replaces browser history entries. A deep restoration creates spurious intermediate history entries.istate invocations start child statecharts in on-entry. The child chart's start! may also be async — the invocation system must propagate this correctly.start-routing! must handle promise-returning start! — either by returning a promise itself or by using the async event loop which handles this naturallyapply-external-route must work correctly when the async processor is in use — the fired routing event will cause async state entries, and the system must not assume synchronous completionistate invocations during restoration must work with async — the invocation processor must handle promise-returning start! on child charts::sc/statechart-src in working memory must be set before any async processing begins so that event routing works during restorationrstate (simple routing) and istate (invoked chart routing)integration/fulcro/ui_routes.cljc — start-routing!, apply-external-route, establish-route-params-node, rstate, istateintegration/fulcro.cljc — start! wrapper must handle async processor return valuesintegration/fulcro/route_history.cljc — History push/replace must respect restoration modeinvocation/statechart.cljc — Child chart start! invocation must propagate asyncalgorithms/v20150901_async_impl.cljc — No changes expected (already handles async on-entry)start-routing!Make start-routing! return a promise when the async processor is used. The initial apply-external-route (fired in the root state's on-entry) triggers deep state entry. The promise resolves when the full configuration is stable.
Key change: scf/start! already delegates to the processor's start!. The Fulcro integration layer needs to handle the promise return and update the Fulcro state atom when it resolves.
Add a ::restoration? key to the event data when apply-external-route fires the routing event. establish-route-params-node checks this flag:
replace-route! only on the final state (skip intermediates)push-route! as todayThe flag propagates through the event data so all on-entry scripts in the path can see it.
Wrap the restoration chain with error handling. If a promise rejects mid-chain:
:error.routing/restoration-failed event is raised with the error and the last good stateEnsure the statechart invocation processor's start-invocation! returns/propagates the promise from the child chart's start!. The parent algorithm already awaits promises in on-entry via the async processor.
start-routing! always use the async processor, or should it auto-detect?istate child charts use the same processor type as the parent?start-routing! with async processor returns promise that resolves to working memory/a/b/c correctly restores to deeply nested state :c passing through :a and :bistate targets with async on-entry in child charts restore correctlyCan you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |