开发者

DOMContentLoaded event firing twice for a single page load

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.on开发者_运维知识库ContentLoaded = 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?


document.addEventListener('DOMContentLoaded', () => {
    console.log('DOMContentLoaded');
    // do stuff
},{ once: true });


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.


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 );


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜