Why FXM should wait for your page to load

Context

Working with FXM, I faced a very interesting sporadic issue: every 10-15 times some of the components were not loading on a page. A response object was identical all the time, no errors in console, no changes in a site code since the last deployments. I think you get the situation.

However, this issue was able to cause a lot of troubles for a client as FXM was used on many legacy sites. So I continued digging…

Research

As usual,  I’ve tried to get into the details of an actions workflow and find potential weak points:

  • A page from an external site loads
  • An FXM beacon script, referenced in a head tag of the page, get parsed by a browser and loads an SCBeacon object, mentioned  at the end of this page.
  • As a part of a constructor of the SCBeacon object, an AJAX request takes place and loads HTML snippets from Sitecore.
  • Once the AJAX request succeeded, a visitSuccess function executes.
  • During execution of it looks for HTML elements using jQuery like selectors and replace (or put something before/after) them with an HTML, got from Sitecore.

As response object is always the same I’ve started looking for reasons why element might not be generated in DOM.

To do that I’ve replaced a beaconApi.js file, that you could find in /Sitecore/shell/client/Services/assets/libs, with un-minified version and put a lot of breakpoints.

What was discovered

During an investigation, I’ve found out that some selectors were not able to return an element object.

var elements = Sizzle(match.Selector, document);

In addition to that, an element was not able to be detected by a document.getElementById(), which is a clear sing DOM beeing not loaded by the moment of execution of this function.

Revolution

We could not move the FXM script to the end of the body, as inline an analytics won’t be available (SCBeacon would be undefined till the end of a page processing). Also, we could not delay the beacon initialization, as it might increase component load time and affect UX.

So the solution is to embed waiting for DOM to be loaded after you got the response from the AJAX request to Sitecore.

var processResponse = function(resp){
  ...
  events.dispatch('ready');
  status = 'ready';
}

var visitSuccess = function(resp) {
  var readyStateCheckInterval = setInterval(function() {
    if (document.readyState === "complete"
      || document.readyState === "interactive" ) {
      clearInterval(readyStateCheckInterval);
      processResponse(resp);
    }
  }, 10);
}

internalService.trackPageVisit().then(visitSuccess).fail(dispatchError);

What you need to notice is that you could not use DOM loaded event, it might be fired earlier, as well as wait for only a complete event, as during an interactive state DOM is ready to be used.

Sitecore ticket: 465566

Additional thoughts

From my perspective, injecting HTML snippets and tracking analytics events are really separate functions, which ideally should be handled by separate scripts:

  • bundle/analytics – loaded in an HTML head and available for an inline scripting.
  • bundle/FXM – an injector script, loaded in the end of DOM, before custom libraries, so it could work with anything already rendered and processed by a browser on a page.

As usual: Share if you like the post. Follow me on twitter @true_shoorik

Why FXM should wait for your page to load

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s