Skip to content

[web-profiler-bundle] Debug toolbar javascript stacks event listeners #37073

Closed
@Seikyo

Description

@Seikyo

Description

When the debug toolbar is enabled each ajax request add two event listeners to the document.

It seems that in base_js.html.twig the method addEventListener is called within the renderAjaxRequests method which is called on each ajax call. This bind new event listeners on each ajax request to the document.

Not sure if it should be feature request or bug report as this is not critical but I was searching why event listeners where stacking and it took me some time to find it.

name     : symfony/web-profiler-bundle
descrip. : Symfony WebProfilerBundle
keywords : 
versions : * v5.0.8

web-profiler-bundle/Resources/views/Profiler/base_js.html.twig

var renderAjaxRequests = function() {
    ()

    addEventListener(document.querySelector('.sf-toolbar-ajax-clear'), 'click', function() {
        requestStack = [];
        renderAjaxRequests();
        successStreak = 4;
        document.querySelector('.sf-toolbar-ajax-request-list').innerHTML = '';
    });
}

Suggestion

I have not fully understood how the toolbar javascript works but moving the addEventListener call on the loadToolbar method after the intial renderAjaxRequests should do the trick. The renderAjaxRequests does not create / remove any html but only work with classes and internal attributes so it seems it should be ok.

Moving it under the loadToolbar removes the event listeners stacking and the ajax call toolbar seems to be ok but I did not test this thoroughly and only with Chrome.

loadToolbar: function(token, newToken) {
    newToken = (newToken || token);
    this.load(
        ()
        renderAjaxRequests();
        addEventListener(document.querySelector('.sf-toolbar-ajax-clear'), 'click', function() {
            requestStack = [];
            renderAjaxRequests();
            successStreak = 4;
            document.querySelector('.sf-toolbar-ajax-request-list').innerHTML = '';
        });
    )
}

Example

Here is the code used to monitor event listeners :

event-tracker.js

window.eventListenerList = [];

Element.prototype.originalAddEventListener = Element.prototype.addEventListener;
Element.prototype.addEventListener = function (type, listener, capture) {
    this.eventListenerList = this.eventListenerList || [];
    this.eventListenerList[type] = this.eventListenerList[type] || [];

    capture = capture || false;
    this.originalAddEventListener(type, listener, capture);


    const event = {
        listener: listener,
        useCapture: capture,
    };
    this.eventListenerList[type].push(event);
    window.eventListenerList.push(event);
};

Element.prototype.getEventListeners = function () {
    this.eventListenerList = this.eventListenerList || {};
    return this.eventListenerList;
};

Element.prototype.originalRemoveEventListener = Element.prototype.removeEventListener;
Element.prototype.removeEventListener = function (type, listener, capture) {
    capture = capture || false;
    this.originalRemoveEventListener(type, listener, capture);

    const event = {
        listener: listener,
        useCapture: capture,
    };

    this.eventListenerList[type] = this.eventListenerList.filter(e => e !== event);
    window.eventListenerList = window.eventListenerList.filter(e => e !== event);
};

On any template using twig with profiler enabled with only the above javascript added :
(input) = type in console and validate

Chrome console

// List page initial event listeners
(input) window.eventListenerList
(5) [{}, {}, {}, {}, {}]

// Do an ajax request and display event listeners again
(input) fetch('https://google.com');
(input) window.eventListenerList
(7) [{}, {}, {}, {}, {}, {}, {}]

// New event listeners informations
(input) window.eventListenerList[6].listener
ƒ () {                requestStack = [];                renderAjaxRequests();                successStreak = 4;                document.querySelector('.sf-toolbar-ajax-request-list').innerHTML = '';   
(input) window.eventListenerList[5].listener
ƒ () {                requestStack = [];                renderAjaxRequests();                successStreak = 4;                document.querySelector('.sf-toolbar-ajax-request-list').innerHTML = '';   

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions