Quill: Performance degradation with DOM mutation events

Created on 13 Oct 2017  路  20Comments  路  Source: quilljs/quill

The usage of DOM mutation events in Quill (specifically, DOMNodeInserted from c4d897838a463d8396c9e93ec9faf5e9bca5566d) significantly degrades the performance of DOM node insertions and removals on the _entire document_. Additionally, the API is deprecated.

More information about the performance effects of DOM mutation events can be found on MDN: https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Mutation_events
In particular:

Adding DOM mutation listeners to a document profoundly degrades the performance of further DOM modifications to that document (making them 1.5 - 7 times slower!). Moreover, removing the listeners does not reverse the damage.

The listener was originally added to address #1437 — I'm not sure _why_ adding mutation listeners would fix that bug, but it would be nice to find another solution.

I have tried substituting the mutation event listener with a MutationObserver, but using MutationObserver doesn't fix the bug.

Steps for Reproduction

  1. Visit https://quilljs.com
  2. Run the following code in console:
document.body.addEventListener('click', () => {
    console.time();
    for (let i = 0; i < 1000; i++) {
        const div = document.createElement('div');
        document.body.appendChild(div);
    }
    console.timeEnd();
});
  1. Click on the page and observe timing information
  2. Run the same code on another site, to compare

Expected behavior:
DOM node insertions are fast

Actual behavior:
DOM node insertions are painfully slow

Platforms:
This seems to affect all major browsers and platforms

Version:
>= 1.2.5, when the listener was added

Most helpful comment

Any plans to do something about this?

All 20 comments

Running on both quilljs.com and google.com results in < 5ms being reported on Chrome. Maybe the platform matters?

馃 I think the difference is a lot more obvious when running the profiler as well -- though that could very well be the overhead associated with profiling events.

However if I use finer timing tools (e.g. performance.mark) to time _only_ the appendChild, I see a slowdown of 2 - 3x

@albertxing I made a simple benchmark to reproduce the performance issue:
https://codepen.io/pmdartus/pen/NXrdgO?editors=1000

Here are the numbers I gathered:

  • Chrome (65): 3x slowdown
  • Firefox (56): ~20% slowdown
  • IE11: No impact

How about only adding the DOMNodeInserted listener when IME input is detected? Add the listener when compositionstart is fired? It won't _fix_ the bug, but it would limit the damage

There must be another way to fix https://github.com/quilljs/quill/issues/1437. Is there any explanation why adding the empty listener even fixes this?
At the moment we are experiencing issues with codeblocks because of https://github.com/quilljs/quill/commit/c4d897838a463d8396c9e93ec9faf5e9bca5566d.
Try pasting around 100 lines of code into the quill playground, select all of it and toggle the code style. This takes less than a second without the listener but 4 or 5 seconds with the listener enabled. The listener is called 11000 times for the 100 lines...

@kevinhend @jhchen I propose we add a new boolean flag to the Quill constructor called compatibilityMode. When set to false, it bypasses adding the DOMNodeInserted listener. To preserve backwards-compatibility, the property should default to true, and require the developer to explicitly set it to false to regain that extra performance.

In the Quill source code:

if (config.compatibilityMode) {
  this.domNode.addEventListener('DOMNodeInserted', function() {});
}

When using Quill:

var editor = new Quill(document.querySelector('.editor'), {
  compatibilityMode: false,
  // ...
});

What do you think? If you'd like, I can submit a PR with my proposed implementation.

Hello,
Wondering if there are any updates on this? I'm experiencing significant delays with deltas containing 5,000+ words and formatting.

I can see that the listener was removed again in https://github.com/quilljs/quill/commit/41a60fbf7cc9d23f4d87c4a88c42bb56157e3432#diff-64791d4c2bd2baa277845f35fac28055

As far as I can tell, this is not yet reflected in 1.3.6 but only in develop (for 2.0?)

Some news here?

Any plans to do something about this?

Project dead ?

Is there a fix for this at the moment or not ?
Using version 1.3.7 can see this warning

polyfills.js:11152 [Violation] Added synchronous DOM mutation listener to a 'DOMNodeInserted' event. Consider using MutationObserver to make the page more responsive.

it causes perf issues especially when you have many quill editors on a page.

Any update?

Yes wondering if theres any updates also?

I think @caleb531's solution is the one to go for here 馃憤

For everybody else that is facing this and wants to fix this in the meanwhile: I deleted the line

this.domNode.addEventListener('dragstart', e => this.handleDragStart(e));

everywhere I could find it in the quill folder in the node_modules of my project and then used https://github.com/ds300/patch-package to create a patch of these changes. The only files you really need to touch are ./dist/quill.js and ./dist/quill.min.js, depending on what you use in your project.

EDIT: ironically, if you want to create a patch for quill using latest patch-package (6.2.2), you'll first have to patch patch-package to be able to create the quill patch using this fix: https://github.com/ds300/patch-package/issues/166.

Any update?

Has this problem been fixed in a new update? I'm running angular 9 and i have this problem too.

Same problem, the report is important on my application. And impossible to find any viable way to solve it.

Any updates regarding this issue?

The proposal from @caleb531 sounds good https://github.com/quilljs/quill/issues/1768#issuecomment-436006492

It would great of we can address this, I get this as warning:

[Violation] Added synchronous DOM mutation listener to a 'DOMNodeInserted' event. Consider using MutationObserver to make the page more responsive.

Screenshot 2020-10-26 at 16 54 12

Was this page helpful?
0 / 5 - 0 ratings

Related issues

CHR15- picture CHR15-  路  3Comments

Kivylius picture Kivylius  路  3Comments

splacentino picture splacentino  路  3Comments

ouhman picture ouhman  路  3Comments

Softvision-MariusComan picture Softvision-MariusComan  路  3Comments