1

I have a header area on a web page with some background images which get cycled through.

They're somewhat high-res, and it's above the fold, so I don't want the browser to start loading any image except the first one.

But I'd also like to randomize the order of the images.

The complication is that I'm using a static web host (Netlify).

Some approaches I've considered:

  • Put the elements in the document as usual, then have Javascript query for them and randomize their order. I'm reluctant, because I think the browser will already be off to the races loading the first image which arrives in the HTML, before it gets randomized to some other position. I want to avoid that.
  • Randomize with some server code. But I don't want to; I'm not going to run a server just for this feature.
  • Write every possible combination, or at least a handful of combinations, as separate HTML files, and randomize via URL rewriting in an edge function. Seems sort of messy. I don't want to use an edge function if I don't have to, since it's just one more quota to worry about.
  • Write some logic in an edge function which intercepts the page response and mutates it. Less messy in terms of files being served, though the code itself will be a lot more messy. Plus the same aversion to running an edge function.

What I want to be able to do is have some JS code run before the browser has even seen the whole HTML response, run some brief logic, and add some markup to the stream. And then I can have the standard order in a <noscript> for people with JS turned off and for search engines which don't want to run JS.

It occurs to me that this is exactly what document.write does, is it not?

All resources say to avoid document.write like the plague. But I wonder if this is a rare valid use case?

<html>
  <body>
    <p>This seems to work, and I kind of think it's not a terrible idea.</p>
    <script type="application/javascript">
      // Standard Fisher-Yates shuffle; not relevant
      function shuffle(array) { let i = array.length, j; while (i != 0) { j = Math.floor(Math.random() * i); i--; [array[i], array[j]] = [array[j], array[i]]; } return array; }

      const paras = [
        "<p>para 1</p>",
        "<p>para 2</p>",
        "<p>para 3</p>",
        "<p>para 4</p>",
      ];
      shuffle(paras);
      document.write(paras.join(""));
    </script>
    <noscript>
      <p>para 1</p>
      <p>para 2</p>
      <p>para 3</p>
      <p>para 4</p>
    </noscript>
    <p>Change my mind.</p>
  </body>
</html>

Is this a terrible idea? Why? Is there a better way to do it, meeting my wishlist?

tremby
  • 9,541
  • 4
  • 55
  • 74
  • 1
    Yes, it's a terrible idea. You could cut the existing elements into `DocumentFragment`, shuffle the fragment and insert to the DOM again. – Teemu Aug 10 '23 at 10:10

1 Answers1

1

Yes, it's not a good idea. That method is very old school and has specific behavior that might change from browser to browser. Please see https://developer.mozilla.org/en-US/docs/Web/API/Document/write for more info.

Just use the modern methods such as:

etc. to shuffle elements around as these are safe for renderer / browser.

Word of advice for your specific use case, though: Browser would need to load Javascript first to make it work your desired way and that might not happen. Images might be still loading in order they are originally in the HTML source. I would advise to move this logic to server, if possible. In the end any Javascript is likely not going to work for your use case. It might be possible not to include images in the document itself and add them later (on load randomized) via JS, that would be my preferred approach.

dusoft
  • 11,289
  • 5
  • 38
  • 44
  • I've already read that document. I don't find it specific enough. If I use DOM manipulation methods like the ones you suggested, I don't think I'm meeting the requirements I set out. The DOM would have to be all parsed and ready, and by that point the images are loading. Overall I'm unconvinced. I just found this post https://stackoverflow.com/q/802854/496046 which appears to support my use case. – tremby Aug 10 '23 at 10:26
  • As I said, build your HTML without any image and then randomize images directly adding them via JS. If you want to have your document.write possibly ignored or causing exceptions that's up to you. – dusoft Aug 10 '23 at 10:29
  • That is a possibility but it'd still mean waiting until the DOM is ready, which I expect means a penalty. Maybe I'll try both ways and benchmark. – tremby Aug 10 '23 at 10:35
  • @tremby You don't have to wait for DOM being ready, only until the elements exist. The "penalty" won't be longer than with `d.w` approach. – Teemu Aug 10 '23 at 10:49
  • I verified what you said to a reasonable amount of confidence through benchmarking @Teemu; I got about the same performance penalty vs the straight-up static version whether I did `document.write` or `innerHTML`. Both have a penalty, however -- it seems like once JS alters the page (even before parsing the rest of the page is finished), the browser does not pick up the image references until the rest of the document has finished parsing. Whereas with the static version, the images start loading before parsing finishes. – tremby Aug 11 '23 at 01:26