diff --git a/bridge/core/html/html_image_element.cc b/bridge/core/html/html_image_element.cc
index 614c68ee8f..981c1170f0 100644
--- a/bridge/core/html/html_image_element.cc
+++ b/bridge/core/html/html_image_element.cc
@@ -34,8 +34,26 @@ AtomicString HTMLImageElement::src() const {
}
void HTMLImageElement::setSrc(const AtomicString& value, ExceptionState& exception_state) {
- SetBindingProperty(binding_call_methods::ksrc, NativeValueConverter::ToNativeValue(ctx(), value),
- exception_state);
+ // Queue a UI command rather than going through the sync bridge path:
+ //
+ // * `src` is fire-and-forget — JS never reads anything synchronously
+ // out of the setter, the actual network load is async on Dart, and
+ // any subsequent `img.src` getter / `getProperty` call calls
+ // `FlushUICommand` internally before its sync read so it still sees
+ // the value just written.
+ // * The sync path forced a per-write FlushUICommand, which during
+ // React commit + image-load swap bursts triggered cascading
+ // styleRecalc walks (~2k recalcs per insert in profiles). Folding
+ // these writes into the next natural flush eliminates the
+ // amplification.
+ //
+ // The HTMLImageElement attribute mirror is unchanged: `attributes_` is
+ // only kept in sync for `WidgetElement`, and the WidgetElement-only
+ // branch in `BindingObject::SetBindingProperty` is preserved by the
+ // remaining sync setters that need it.
+ SetBindingPropertyAsync(binding_call_methods::ksrc,
+ NativeValueConverter::ToNativeValue(ctx(), value),
+ exception_state);
if (!value.IsEmpty() && !keep_alive) {
KeepAlive();
keep_alive = true;