简体   繁体   中英

Editable HTML content is very laggy when it is large

For example, I have the following simple HTML page, where the <span>[SOME FIELD]</span> is repeating many times to make up for about 200K of the file size:

<!DOCTYPE html>
<html>
<head>
</head>
<body editableContent="true">
        <span>[SOME FIELD]</span>
        <span>[SOME FIELD]</span>
...
        <span>[SOME FIELD]</span>
</body>
</html>

As the content grows, the editing experience is becoming very laggy. It's literally impossible to type or edit the content.

Here is a complete repro case . To see what I mean, just move the cursor to the end of the editable content and try editing. It lags big time under IE and Chrome , making it almost impossible to type. It works great under Firefox , though.

The problem: I need to get it working reasonably fast under IE.

So far, I got close with IE8 emulation (with <meta http-equiv="X-UA-Compatible" content="IE=8"> ), so this works (under IE).

However, I need to support IE=edge , too. Any advice on how to make this happen would be greatly appreciated. IMO, it's a bug (which I submitted here for IE and here for Chrome ), but I'm looking for any workaround.

Updated , a bounty is offered for any solution that works while loaded in stand-alone IE browser or a custom application hosting WebBrowser control , using IE=edge HTML document mode.

Updated , the corresponding IE bug reported was just closed as "Won't fix".

Why not break the data down and store it in an array or Json object and only read a portion at a time, updating as the user scrolls or moves through the content. This way only a small portion will being processed at any point in time. If you use Jquery you could get the id from the class reference. If you don't want to use Jquery you could write a class identifier function in raw Javascript. The below is rough but you can get the idea.

<!DOCTYPE html>
<html>
<head>
</head>
<body editableContent="true">
    <span id="item1" class="handle_items">[SOME FIELD]</span>
    <span id="item2" class="handle_items">[SOME FIELD]</span>
    ...
    <span id="item-n" class="handle_items">[SOME FIELD]</span>
</body>
</html>

<script>
$(function(){

    var arrayData = [];

    $(".handle_items").mouseover(function() {
        var identVar = $( this ).prop('id');
        fillHtml(identVar);
    });

    function fillHtml(identVar) {
        $("#" + identVar).html(arrayData[i]);
    }
});
</script>

使用鼠标或SHIFT + ARROW选择一个字符,然后通过按DELETE删除将在IE中将编辑速度恢复为正常。

One solution would be to not use contenteditable = true for entire area (body section in your case). You can determine the visible area of the body, create a ' Range ' for the respective area and temporarily wrap it in an element with contenteditable = true .

However, depending on more detailed requirements, this approach might not be suitable. For example, one problem that comes to my mind is trying to maintain caret position after scrolling only a few rows.

After a lot of blind shooting, I think I've found something that might actually work:

  1. Copy the large chunk of HTML into the clipboard
  2. Paste it over whatever content is inside the editable area
  3. Voilà, the lagging while editing seems to have been gone

Presumably, both steps can be done programmatically.

In all browsers the more elements the slower they get. The other thing that causes problems are memory leaks. Most large frameworks, like angular or knockout cause memory leaks. You can profile those by running a memory snapshot in the memory profiler.

As far as elements you really want to keep that under a thousand I'd you can. You can add and remove elements as needed they way good continuous scrollers do.

I have no IE to check performance right now, anyway in Chrome (Ubuntu) this do help. I just remove contenteditable from root element and add it to each span .

This make content editing pretty fast.

You can check this is Chrome with next steps:

  1. in devtools (elements panel) select root node of editor (that is body with contenteditable attribute)

  2. got to devtools javascript console

  3. execute this code snippet:

Snippet:

var nodes = $0.querySelectorAll('span');
$0.setAttribute('contenteditable', false)
for (var i = 0, max = nodes.length; i < max; i++) {
    nodes[i].setAttribute('contenteditable', true);
}

You said that you didn't want to use pagination because...

I can't see how AJAX/pagination can help with editable content. In reality, it's a full-featured editor similar to Word. Eg, it has a contextual spellchecker, which depends on the words around the cursor. Or how the user can select a block of text that spans multiple pages.

However, you can use pagination (or something similar) while still allowing these features. Basically, you need to only load the currently relevant lines.

I know Objective-C, and this problem is very similar to UITableViewControllers. They combat the issue by displaying the table elements that are currently being viewed, and deallocating the others. In your case, you would want to store their information in a JavaScript array.

The way I would go about it is to create a loadItem function and an unloadItem function. loadItem would get the contents of an item and add it to the body, and unloadItem would copy the contents back to the array and remove the item (probably by setting the style visibility:hidden , but I haven't checked to see if it works).

To find the currently relevant lines:

  • Anything that is on the screen
  • Anything that is part of a selection
  • Anything else that might come up that should be displayed

As lines are unselected, go off the screen, or anything else that renders them no longer needed, call unloadItem() and pass it the line number/whatever identifies the line.

EDIT: This is what I mean:

 for(var count=0;count<1000;count++){ document.getElementById("main").innerHTML+="<span id='item"+count+"'>[SOME FIELD "+count+"]</span>"; } function loadItem(number){ document.getElementById("item"+number).style.visibility="visible"; } function unloadItem(number){ document.getElementById("item"+number).style.visibility="hidden"; } unloadItem(1); unloadItem(2); loadItem(1); // I didn't have time to implement the rest. Basically, when a user is not viewing a line, it should be hidden. When they scroll to view it, it should show up again. I haven't tested this yet, but it should work. // There is supposed to be a bit of slowness when it loads, it is creating all the content and that is normal. 
 <!DOCTYPE html> <html> <head> </head> <body contenteditable="true" id="main"> </body> </html> 

  1. I think you should make each span tag editable and show limited number of spans at a time . this will help in better loading of your web page. and content will be easily editable .
  2. additionally you can do editableContent="true" if user wants to edit more than one span tag at the same time time. which is a bit surprising because if your file contains 200k size , someone will rarely edit multiple content at same time. whenever a user clicks to edit whole webpage, create a pop up with simple basic html layout and let user to change whatever he wants. it will load properly in basic layout popup window.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM