The main thread is a single lane

Tap a trade button and nothing happens for a full second. That is not an isolated bug — it is the ceiling of the model. In a browser or WebView, the JavaScript engine and rendering share one main thread: script execution, layout, paint, and input response all compete for the same lane. The moment a long task appears — heavy computation, a large JSON parse, framework hydration, third-party tags — paint and input are blocked. web.dev defines Total Blocking Time plainly: any task over 50 ms is a "long task" that blocks the main thread; the 2025 Web Almanac measured a mobile median TBT of 1,916 ms, rising to 7,555 ms at the 90th percentile. The same script that runs smoothly on a laptop can freeze a mid-range phone for more than a second.

WebView: one thread does everything

In a browser and in WebView, the JS engine and the renderer live on the same main thread. A long task — heavy calculation, a giant JSON parse, framework hydration, third-party tags — blocks both paint and input at once. The user's tap already fired, but the browser must wait for the task to finish before it can respond. This is the structural ceiling H5 hits on mobile: your own logic and "make the screen move" fight over the same thread.

Mini-program: logic and render are separate

WeChat's dual-thread model splits the two apart. The logic layer runs JavaScript in an isolated engine — JavaScriptCore on iOS, V8/X5 on Android — with no DOM. The render layer is a WebView that only paints WXML/WXSS. They cannot share memory; they communicate only through the Native bridge via setData, where data is serialized, diffed, and applied to the view. So a heavy calculation in the logic thread does not freeze the render thread's painting. Because the render layer's own work is light, it keeps answering the user's touch.

Honestly, setData itself has a cost — serialization, diffing, and cross-thread transfer. A large or overly frequent setData can cause its own jank. So the real win is "compute no longer blocks paint," but you must keep setData lean. WeChat's Skyline is a newer rendering engine that pushes even closer to native.

Where the smoothness comes from

  • Separation of concerns. Heavy compute and paint are isolated; they never wait on each other.
  • Light render thread. It only diffs and paints — it does not run business logic.
  • Native mediation. The bridge batches and forwards; the render layer does not wait on your loop.
  • Predictable on mobile. The jank that dogs H5 on mid-range phones is structurally reduced.

Side by side

DimensionWebView / H5Mini-Program
Thread modelSingle main thread (JS + layout + paint + input)Dual: logic engine + render WebView
Long-task impactBlocks paint + input (frozen taps)Compute isolated; render keeps painting
Mobile median TBT1,916 ms; 7,555 ms at p90Render thread off the JS-critical path
DOM in logic layerYes (can block directly)No DOM; update only via setData
Cost to watchUnbounded JavaScriptsetData size / frequency
Best forOpen-web contentIn-host transactional UI

What it means for your flow

For a trading UI, a chat, or a form, responsiveness is the product. Moving the transactional core into a mini-program structurally removes the "one thread does everything" ceiling that H5 slams into on mid-range phones. H5 is right for the open web; the in-host core should not share its main thread with its own heavy logic.

Where Cross Mini App fits

Cross Mini App is the runtime and the open catalog for the dual-thread model. Build once, run in any host with logic and render separated by a governed bridge, so heavy compute never steals a frame from the tap. H5 stays the door; the mini-program is the room where the button always answers.

Sources