1

The project is to process and visualize high dimensional data. And we need to replace some text after the data has been loaded to the website. I found some threads on stackoverflow with more or less the same solution Replace text in HTML page with jQuery:

 $('body :not(script)').contents().filter(function() {
  return this.nodeType === 3;
 }).replaceWith(function() {
  return this.nodeValue.replace('-9o0-9909','The new string');
 });

And this solution works well, it replaces exactly the searched text (regex) with the html code (e.g. 'word').Adding superscript tags around all trademark and registered trademark symbolsReplace ALL words in HTML or Swapping text in a DOM element with children JavaScript/jQuery. The problem is that we have to replace 10,000+ words and it takes a while. The time is not the issue, but the browser freezes during that process and you can't do anything. How can we avoid freezing the browser? I read about lazy loading for images and asynchronous functions, but I don't know how to apply this to text replacement. Any help is appreciated?

Edit: Here a jsfiddle

Luz
  • 11
  • 3
  • One thing that can slow thing down dramatically when manipulating the DOM is document reflow. To solve this you could try detaching the section you are parsing, and the re-attach. – Keith Jul 22 '20 at 07:38
  • @Keith has a good suggestion, but I don't see you can do it. Maybe React can help with that. I don't know if browsers are capable of doing an asynchronous task once the elements are unmounted from the DOM. – Debargha Roy Jul 22 '20 at 07:44
  • @DebarghaRoy I've posted an example, unmounted DOM elements are totally valid, Javascript's Garbage collector handles this without issues, even if you wanted to use async methods.. – Keith Jul 22 '20 at 08:15

1 Answers1

1

Whenever you manipulate the DOM directly, it's often slow because the browser may try to do a document reflow as your updating.

To prevent this, one idea is just to remove the section from the DOM, and then manipulate it while it's detached, and when done just re-attach back to the DOM, the browser will then only need to do 1 single document reflow.

Below is a simple example, I create some 100,000 char dummy HTML with random Xs in, you can then click the button and it will then surround all the X with the B (bold) tag. And as you will see when you click the button it's pretty much instant.

const d = document.createElement('div');
const a = (new Array(100000)).fill('_');
for (let l = 0; l < a.length; l += 1) {
  const r = Math.random();
  if (r < 0.1) a[l] = '<br/>'
  else if (r < 0.2) a[l] = 'X';
  

}
d.innerHTML = a.join('');
document.body.appendChild(d);

document.querySelector('button').addEventListener('click', () => { 
  d.remove();
  d.innerHTML = d.innerHTML.replace(/X/g, '<B>X</B>');
  document.body.appendChild(d);
});
<button>Bold X</button>
Keith
  • 22,005
  • 2
  • 27
  • 44
  • Hi Keith, first thank you for your answer. I already learn something new. So you say before the line "return this.nodeValue.replace('-9o0-9909','The new string');" I should remove "this.nodeValue" and then reattach it? And how am I doing that in the function that I posted? I'm new to the stuff and the DOM things are complicated for me right now. I'm happy that I found a working solution :) Or do I have to rewrite the whole thing? – Luz Jul 22 '20 at 09:12
  • @Luz It's hard to say how to do it specifically in your case, as you have not shown your html. But the concept is the same however you do things. If you want to use jQuery use the detach method instead, as thats more akin to a pure DOM remove. https://api.jquery.com/detach/. – Keith Jul 22 '20 at 09:21
  • the html is not that important. We have a guys who is familiar with regular expression and he said that we can grab everything with regular expressions. So the important stuff is to be able use regex and replace it with html code and then also to be able to use 'body :not(script):not(.do-not-replace):not(textarea)'. So to exclude stuff you don't want to replace. So maybe I could split up the function I posted. Then maybe try to somehow remove the "this.nodeType", save it before removing, so that I can replace the stuff. And how do I attach it back in the right place? – Luz Jul 22 '20 at 11:18
  • @Luz. To put back into the right place, I would just use another div as a container, and you can add and remove at will. All your jQuery code will still work while detached. If after doing this things are still locking up, you could maybe split your operation using some async loops, but first I would see if doing this makes it fast enough anyway. – Keith Jul 22 '20 at 11:31
  • sorry for the stupid question, but I don't know what you mean with the div :( Here I created a jsfiddle https://jsfiddle.net/bdvthxer/6/ And I don't know how to create async loops. I tried to the async to the function, but then the html content is gone, because the replaceWIth is getting Promises as a answer and not the node that was replaced. Damn I didn't thought that replacing html would get so complicated :( – Luz Jul 22 '20 at 12:26