Bug 1905646 Comment 1 Edit History

Note: The actual edited comment in the bug view page will always show the original commenter’s name and original timestamp.

So far, here's what I observed:

The `for (u in ve(t, l), s = l)` below iterates over the properties from the above,
and the property value flows into `b(e, u, c, i)`:

https://www.ubereats.com/_static/client-vendor-react-57d02f50089116f6.js
```js
    function Bo(e, n, t) {
      var r = n.pendingProps;
      switch (Gl(n), n.tag) {
...
        case 5:
          tu(n);
          var l = Za(Ga.current);
          if (t = n.type, null !== e && null != n.stateNode) Po(e, n, t, r),
          e.ref !== n.ref && (n.flags |= 512, n.flags |= 2097152);
           else {
...
            if (e = Za(Ya.current), oa(n)) {
...
            } else {
...
              e: {
...
                for (u in ve(t, l), s = l) if (s.hasOwnProperty(u)) {
                  var c = s[u];
                  'style' === u
                    ? he(e, c)
                    : 'dangerouslySetInnerHTML' === u
                      ? null != (c = c ? c.__html : void 0) && ce(e, c)
                      : 'children' === u
                        ? 'string' == typeof c
                          ? ('textarea' !== t || '' !== c) && fe(e, c)
                          : 'number' == typeof c && fe(e, '' + c)
                        : 'suppressContentEditableWarning' !== u &&
                          'suppressHydrationWarning' !== u &&
                          'autoFocus' !== u &&
                          (o.hasOwnProperty(u)
                           ? null != c && 'onScroll' === u && Mr('scroll', e)
                           : null != c && b(e, u, c, i))
                }
```

`b(e, u, c, i)` performs `setAttribute` on the `img` element.
At this point, the `img` element doesn't have parent node.

https://www.ubereats.com/_static/client-vendor-react-57d02f50089116f6.js
```js
    function b(e, n, t, r) {
...
      }(n) &&
      (null === t
       ? e.removeAttribute(n)
       : e.setAttribute(n, '' + t))
     : l.mustUseProperty
       ? e[l.propertyName] = null === t
         ? 3 !== l.type && ''
         : t
       : (n = l.attributeName,
          r = l.attributeNamespace,
          null === t
          ? e.removeAttribute(n)
          : (t = 3 === (l = l.type) ||
             4 === l &&
             !0 === t
             ? ''
             : '' + t,
             r
             ? e.setAttributeNS(r, n, t)
             : e.setAttribute(n, t))))
```

After all attributes are populates (including both `src` and `srcset`),
the element is *somehow* connected to the document, and then it causes the `error` event.

Then, after that, yet another `setAttribute` call happens t times in the following

https://www.ubereats.com/_static/client-vendor-react-57d02f50089116f6.js

```js
    function di(e, n) {
      var t = e.alternate,
      r = e.flags;
      switch (e.tag) {
...
        case 5:
...
          if (4 & r && null != (l = e.stateNode)) {
...
            if (e.updateQueue = null, null !== s) try {
              'input' === i && 'radio' === u.type && null != u.name && G(l, u),
              ye(i, o);
              var c = ye(i, u);
              for (o = 0; o < s.length; o += 2) {
                var f = s[o],
                d = s[o + 1];
                'style' === f
                  ? he(l, d)
                  : 'dangerouslySetInnerHTML' === f
                    ? ce(l, d)
                    : 'children' === f
                      ? fe(l, d)
                      : b(l, f, d, c)
```

and then `load` event is dispatched on the `img` element twice.

There's no difference in the element attributes between:
  * after `for (u in ve(t, l), s = l)` loop, and
  * after `for (o = 0; o < s.length; o += 2)` loop

So at least the difference between `error` vs `load` doesn't seem to be caused by the attributes themselves.

Then, one thing I notice is that, the behavior for the following case differs between Firefox vs Chromium/Safari
  * `img` element is not attached to the tree
  * `img` element has `src` attribute with empty string
  * `img` element has `srcset` attribute with valid sources
  * `img` element has `loading` attribute with `lazy` value

testcase:
`data:text/html,<script>const img = document.createElement("img"); img.onload = () => { console.log("load"); }; img.onerror = ( ) => { console.log("error"); }; img.setAttribute("src", ""); img.setAttribute("srcset", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAADElEQVQI12NgYPgPAAEDAQDZqt2zAAAAAElFTkSuQmCC 100w, data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAADElEQVQI12NgYPgPAAEDAQDZqt2zAAAAAElFTkSuQmCC 200w"); img.setAttribute("loading", "lazy");</script>`

Firefox shows `error`, but Chromium/Safari show `load`.

So, the possibility is that, there's some delay between setting attributes and attaching to the tree, and `error` event happens only on Firefox, and it applies the `visibility: hidden`, and then the image loads properly once the `img` is attached to the tree.
So far, here's what I observed:

The `for (u in ve(t, l), s = l)` below iterates over the properties from the above,
and the property value flows into `b(e, u, c, i)`:

https://www.ubereats.com/_static/client-vendor-react-57d02f50089116f6.js
```js
    function Bo(e, n, t) {
      var r = n.pendingProps;
      switch (Gl(n), n.tag) {
...
        case 5:
          tu(n);
          var l = Za(Ga.current);
          if (t = n.type, null !== e && null != n.stateNode) Po(e, n, t, r),
          e.ref !== n.ref && (n.flags |= 512, n.flags |= 2097152);
           else {
...
            if (e = Za(Ya.current), oa(n)) {
...
            } else {
...
              e: {
...
                for (u in ve(t, l), s = l) if (s.hasOwnProperty(u)) {
                  var c = s[u];
                  'style' === u
                    ? he(e, c)
                    : 'dangerouslySetInnerHTML' === u
                      ? null != (c = c ? c.__html : void 0) && ce(e, c)
                      : 'children' === u
                        ? 'string' == typeof c
                          ? ('textarea' !== t || '' !== c) && fe(e, c)
                          : 'number' == typeof c && fe(e, '' + c)
                        : 'suppressContentEditableWarning' !== u &&
                          'suppressHydrationWarning' !== u &&
                          'autoFocus' !== u &&
                          (o.hasOwnProperty(u)
                           ? null != c && 'onScroll' === u && Mr('scroll', e)
                           : null != c && b(e, u, c, i))
                }
```

`b(e, u, c, i)` performs `setAttribute` on the `img` element.
At this point, the `img` element doesn't have parent node.

https://www.ubereats.com/_static/client-vendor-react-57d02f50089116f6.js
```js
    function b(e, n, t, r) {
...
      }(n) &&
      (null === t
       ? e.removeAttribute(n)
       : e.setAttribute(n, '' + t))
     : l.mustUseProperty
       ? e[l.propertyName] = null === t
         ? 3 !== l.type && ''
         : t
       : (n = l.attributeName,
          r = l.attributeNamespace,
          null === t
          ? e.removeAttribute(n)
          : (t = 3 === (l = l.type) ||
             4 === l &&
             !0 === t
             ? ''
             : '' + t,
             r
             ? e.setAttributeNS(r, n, t)
             : e.setAttribute(n, t))))
```

After all attributes are populates (including both `src` and `srcset`),
the element is *somehow* connected to the document, and then (or maybe before get connected?) it causes the `error` event.

Then, after that, yet another `setAttribute` call happens t times in the following
(at this point, `img` has parent node)

https://www.ubereats.com/_static/client-vendor-react-57d02f50089116f6.js

```js
    function di(e, n) {
      var t = e.alternate,
      r = e.flags;
      switch (e.tag) {
...
        case 5:
...
          if (4 & r && null != (l = e.stateNode)) {
...
            if (e.updateQueue = null, null !== s) try {
              'input' === i && 'radio' === u.type && null != u.name && G(l, u),
              ye(i, o);
              var c = ye(i, u);
              for (o = 0; o < s.length; o += 2) {
                var f = s[o],
                d = s[o + 1];
                'style' === f
                  ? he(l, d)
                  : 'dangerouslySetInnerHTML' === f
                    ? ce(l, d)
                    : 'children' === f
                      ? fe(l, d)
                      : b(l, f, d, c)
```

and then `load` event is dispatched on the `img` element twice.

There's no difference in the element attributes between:
  * after `for (u in ve(t, l), s = l)` loop, and
  * after `for (o = 0; o < s.length; o += 2)` loop

So at least the difference between `error` vs `load` doesn't seem to be caused by the attributes themselves.

Then, one thing I notice is that, the behavior for the following case differs between Firefox vs Chromium/Safari
  * `img` element is not attached to the tree
  * `img` element has `src` attribute with empty string
  * `img` element has `srcset` attribute with valid sources
  * `img` element has `loading` attribute with `lazy` value

testcase:
`data:text/html,<script>const img = document.createElement("img"); img.onload = () => { console.log("load"); }; img.onerror = ( ) => { console.log("error"); }; img.setAttribute("src", ""); img.setAttribute("srcset", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAADElEQVQI12NgYPgPAAEDAQDZqt2zAAAAAElFTkSuQmCC 100w, data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAADElEQVQI12NgYPgPAAEDAQDZqt2zAAAAAElFTkSuQmCC 200w"); img.setAttribute("loading", "lazy");</script>`

Firefox shows `error`, but Chromium/Safari show `load`.

So, the possibility is that, there's some delay between setting attributes and attaching to the tree, and `error` event happens only on Firefox, and it applies the `visibility: hidden`, and then the image loads properly once the `img` is attached to the tree.

Back to Bug 1905646 Comment 1