2

I came across this third-party analysis code known as VWO, the embedded script is interesting, and the official documentation is available here: https://help.vwo.com/hc/en-us/articles/360021306233-Volusion

Thus the interesting code in their documentation is as follows:

           load: function(a) {
               var b = d.createElement('script');
               b.src = a;
               b.type = 'text/javascript';
               b.innerText;
               b.onerror = function() {
                   _vwo_code.finish();
               };
               d.getElementsByTagName('head')[0].appendChild(b);
           },

Here is a section of their embedded code; I saw that b.innerText accomplished nothing, and I was curious what occurred exactly there. Is this a browser engineering level trick?

I'm aware that some kind of code will cause the browser to force paint, but this doesn't appear to be the case.

Anybody have any ideas?

Joseph
  • 3,974
  • 7
  • 34
  • 67
  • The code is basically trying to create ` – Joshua Ooi Feb 24 '23 at 09:17
  • 1
    Yes, I know, I'm curious about the `innerText` part. – Joseph Feb 24 '23 at 11:02
  • 2
    `innerText` doesn't force paint, but layout recalculation in the middle of the script execution (only when there's a pending change in the layout). In the example the element is off-layout, and not even in the DOM, hence as you've stated, this can't be the purpose. I doubt the line is there for nothing, it's probably a piece of developement time relict, they've just forgotten to remove it. Perhaps the code was meant to create an inline script instead of loadable script. – Teemu Feb 24 '23 at 11:12

2 Answers2

3

This was added to support the IE browser in the past. We will re-evaluate this to see if this is still required for any of the available browser versions.

2

You forgot to include some very important details on the code:

         load: function(a) {
               var b = d.createElement('script');
               b.src = a;
               b.type = 'text/javascript';
               b.innerText;
               b.onerror = function() {
                   _vwo_code.finish();
               };
               d.getElementsByTagName('head')[0].appendChild(b);
           },
           init: function() {
               settings_timer = setTimeout('_vwo_code.finish()', settings_tolerance);
               var a = d.createElement('style'),
                   b = 'body{opacity:0 !important;filter:alpha(opacity=0) !important;background:none !important;}',
                   h = d.getElementsByTagName('head')[0];
               a.setAttribute('id', '_vis_opt_path_hides');
               a.setAttribute('type', 'text/css');
               if (a.styleSheet) a.styleSheet.cssText = b;
               else a.appendChild(d.createTextNode(b));
               h.appendChild(a);
               this.load('//dev.visualwebsiteoptimizer.com/j.php?a=' + account_id + '&u=' + encodeURIComponent(d.URL) + '&r=' + Math.random());
               return settings_timer;
           }

Before they call this load method, they do insert a <style> element.

Given this <style>'s content, I'd suspect (didn't check the imported JS) they actually want to trigger a reflow before the script gets executed so that the body { opacity: 0 } rule is computed before (I guess once again), the script triggers a transition on this CSS property. Failing to do so, the renderer would only see the last value set and wouldn't have anything to transition from.

Why did they not trigger this after the <script> is in the DOM?
There could be a risk of having the script executed before the next painting frame and hence before the next automatic reflow.

Why did they not integrate the forced reflow inside the script directly?
No idea.

BUT

There is a but, as spotted by Teemu, they call the innerText getter on b, which isn't in the DOM yet and thus wouldn't trigger a reflow. They probably meant to call another element's one (e.g document.body), but this code will actually do nothing.

Kaiido
  • 123,334
  • 13
  • 219
  • 285
  • But the element is not in the DOM yet, reading its `innerText` shouldn't trigger any recalculations in the DOM ..? – Teemu Feb 24 '23 at 11:35
  • @Teemu the ` – Kaiido Feb 24 '23 at 11:38
  • @Teemu added the part OP failed to extract. – Kaiido Feb 24 '23 at 11:40
  • Thank you very much! I can't believe I overlooked the style tag! I believe your answer is right! – Joseph Feb 24 '23 at 11:47
  • 1
    But but ... We often create elements out of the DOM, to a JS variable or DocumentFragment, just to avoid reflows, why retrieving `innerText` of an off-DOM element would trigger reflow on DOM? – Teemu Feb 24 '23 at 11:49
  • 2
    @Teemu, Dang! you're right I completely missed they call it on `b`. That's an oversight on their part (and mine). Well spotted. – Kaiido Feb 24 '23 at 11:53
  • 2
    @Teemu given all their ugly shortcuts `d -> document`, `h -> document.head` I guess the one who wrote this was used to have `b -> document.body`somewhere in its codebase... – Kaiido Feb 24 '23 at 11:59