FortAwesome / Font-Awesome

The iconic SVG, font, and CSS toolkit
https://fontawesome.com
Other
73.5k stars 12.2k forks source link

MUTATION_OBSERVER poor performance (observe method) #14368

Open rafalpospiech opened 5 years ago

rafalpospiech commented 5 years ago

There is a huge performance drop while MUTATION_OBSERVER is enabled. I have component on my page that uses SVG to display some content. This content is reactive and works on vue. There are a lot of mutations going on so MUTATION_OBSERVER is running like crazy all the time. I don't want to disable observer globally. Is there a way to exclude from observation some parts of the page? by class or id?

I'm using Font Awesome Free 5.5.0

chrome_2018-12-06_13-11-24 observer

tagliala commented 5 years ago

Hi!

Thanks for being part of the Font Awesome Community.

@robmadole could you please take a look at this?

rafalpospiech commented 5 years ago

Mutation observer is attached to my <g> element inside svg component. This component does not use font-awesome icons at all.

robmadole commented 5 years ago

@rafalpospiech the MutationObserver by it's very nature needs to examine changes to the DOM to see if there is are any changes that it needs to generate icons for. There is currently no way to tell it to ignore certain parts of the page. You can control where the mutation observers starts, though. I don't know if this will help you or not.

You mentioned that you are using Vue. Can you switch to our Vue component?

rafalpospiech commented 5 years ago

No, Vue is used just by this one component :/

rafalpospiech commented 5 years ago

But take a look at this example (line 23)

https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver#Example

You can observe specific nodes only without subtree and with childnodes only.

So theoretically we can get all elements on the page and observe only those that doesn't have an attribute let say data-fa-no-observer or something like that with multiple observers I think.

If observer will be on each element there could be an option to specify which elements to observe and which exclude from observation. For example

{
/* ... */
observer:{
  include:[],
  exclude:[]
}
/* ... */
}

Or by default observe all excluding those with data-fa-no-observer. This would improve the performance a lot.

robmadole commented 5 years ago

@rafalpospiech when brand new elements are added to the page how would we detect those?

And with regard to your include and exclude options. Those elements would still need to be observed are you thinking that we could just bail out of processing them sooner?

dguettler commented 4 years ago

I know this is an old thread, and I don't have a solution to offer. Just adding an example I have been observing. XHR call is adding a rather long dropdown menu, prior to using the fontawesome.js file this took roughly 1-2 seconds to render upon call completion. When using frontawesome.js (5.2 in this case) rendering takes about 15 seconds.

Screen Shot 2020-08-26 at 10 24 26 AM
DibyodyutiMondal commented 1 year ago

Same issue with angular 15 and fontawesome 6

While the icons are used in a static part of the page, the main portion (which is a calendar) renders many, many many dom elements. Adding fontawesome drops performance from 3s for a complex year view to an entire minute and a half!

dbrgn commented 8 months ago

I'm having this problem as well in a SvelteKit application that builds a page that contains hundreds of icons. The FontAwesome mutation observer blocked the UI thread for around 8s on page load.

I resolved it by using FontAwesome in pure CSS mode (CSS + WebFont, no JS).

robmadole commented 7 months ago

@dbrgn you can also take a look at https://github.com/FortAwesome/svelte-fontawesome

dbrgn commented 7 months ago

@robmadole I tried, but https://github.com/FortAwesome/svelte-fontawesome/issues/7

In the end, I'm actually happier with a pure-CSS mode, I don't need any of the dynamic features 🙂

davidAtInleague commented 3 weeks ago

I just hit this drawing some SVGs in a Vue app. Would it be feasible/useful to expose something like FontAwesome.disconnectGlobalObserver() and FontAwesome.restartGlobalObserver() (thin wrappers over MutationObserver's disconnect/observe methods)? And then switch it off/on via Vue's beforeUpdate and updated lifecycle hooks.

edit: I'm using 6.5.2, and I see noAuto from

import { noAuto } from "@fortawesome/fontawesome-svg-core";

That looks like it will disable the observer, don't see anything regarding turning it back on though.