DOMContentLoaded event firing twice for a single page load
Asked Answered
T

4

16

I authored a Firefox add-on several months ago that recently failed. The add-on basically looks for a particular URL and then modifies the DOM for the page. I traced the failure to the (accidental) installation of the "AVG Safe Search" add-on. I found that, with the AVG add-on disabled, the DOMContentLoaded event fires once for the document (behavior I originally expected), but with it enabled, the DOMContentLoaded event fires twice for the document. My add-on inserts a column into an HTML table, so because the event fires twice, two duplicate columns are inserted rather than one.

Here's the distilled initialization code of my add-on:

var hLoadListener = function(event) { myAddon.initialize(event); }
var hContentLoadedListener = function(event) { myAddon.onContentLoaded(event); }

myAddon.initialize = function(aEvent)
{
    gBrowser.addEventListener("DOMContentLoaded", hContentLoadedListener, false);
};

myAddon.onContentLoaded = function(aEvent)
{
    if (!(aEvent.originalTarget.nodeName === "#document")) { return; }

    var doc = aEvent.target; // document that triggered "onload" event

    if (!(doc instanceof HTMLDocument)) { return; }
    if (!doc.location) { return; }

    var href = doc.location.href; // URL of current page

    if (URLRegExp.test(href))
    {
      // Modify the page's DOM
    }
};

window.addEventListener("load", hLoadListener, false);

This issue seems easy to fix by inserting a unique DOM element and then testing for it's existence at the start. My question is whether add-on developers should expect this event behavior as normal or whether this issue is primarily a bug/side-effect in the AVG add-on?

Text answered 4/12, 2010 at 19:22 Comment(0)
N
3

I don't know if I would consider this "normal" however the possibilities for outside applications to affect the operation of your plugin are endless.

That said, I think regardless of AVG causing this anomoly, the smart thing to do, like you said, is to check if the column exists prior to insertion, as AVG may not be the only outside application that influences firefox event triggers.

I am very weary of the DOM driven events because in my own plugin, and the testing of it throughout development has shown PLENTY of anomolies based on so many variables (different OS, different version of FF, different applications on host computer, different plugins within any given users FF, etc..)

To summarize:

  • Bug in AVG? Maybe.
  • Is the potential there for your plugin performance to be affected by MANY other sources? Absolutely!
  • Solution: IMHO- Always check to see if your change has been made prior to making the actual change for all DOM items just to be safe.
Nearby answered 20/12, 2010 at 16:11 Comment(1)
So does it mean that we need to do extra work like the author said that he inserts unique id to stop multiple calls?Multiversity
S
8

addEventListener takes a once parameter. The MDN docs say:

A boolean value indicating that the listener should be invoked at most once after being added. If true, the listener would be automatically removed when invoked. If not specified, defaults to false.

https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#parameters

Example:

document.addEventListener('DOMContentLoaded', () => {
    console.log('DOMContentLoaded');
    // do stuff
}, { once: true });
Salomesalomi answered 30/6, 2022 at 7:40 Comment(1)
Please read How do I write a good answer?. While this code block may answer the OP's question, this answer would be much more useful if you explain how this code is different from the code in the question, what you've changed, why you've changed it and why that solves the problem without introducing others.Sociability
N
3

I don't know if I would consider this "normal" however the possibilities for outside applications to affect the operation of your plugin are endless.

That said, I think regardless of AVG causing this anomoly, the smart thing to do, like you said, is to check if the column exists prior to insertion, as AVG may not be the only outside application that influences firefox event triggers.

I am very weary of the DOM driven events because in my own plugin, and the testing of it throughout development has shown PLENTY of anomolies based on so many variables (different OS, different version of FF, different applications on host computer, different plugins within any given users FF, etc..)

To summarize:

  • Bug in AVG? Maybe.
  • Is the potential there for your plugin performance to be affected by MANY other sources? Absolutely!
  • Solution: IMHO- Always check to see if your change has been made prior to making the actual change for all DOM items just to be safe.
Nearby answered 20/12, 2010 at 16:11 Comment(1)
So does it mean that we need to do extra work like the author said that he inserts unique id to stop multiple calls?Multiversity
D
0

Try to read bindReady method of jquery :

https://github.com/jquery/jquery/blob/master/src/core.js

You will find:

if ( readyBound ) {
 return;
}
readyBound = true;

// Use the handy event callback
document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
// A fallback to window.onload, that will always work
window.addEventListener( "load", jQuery.ready, false );
Dave answered 20/12, 2010 at 19:5 Comment(0)
L
0

My reason for this is a little niche but will add in case it helps anyone.

I'm running VueJS which doesn't like embedded <style> or <script> tags in the middle of the application. I therefore have a script that finds and moves them into the <head> before Vue encounters them.

Ofcourse, the moving of the event listener causes it to be set for a second time when added back into the DOM.

Solution to my problem:

  • Add id="some-id" to script
  • After DOMContentLoaded event listener has been registered add:
  • document.getElementById('some-id').outerHTML = '';

This keeps Vue happy and allows including scripts mid application.

Loadstone answered 31/1, 2020 at 11:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.