0

我写了一个很大的函数来更新我网站上的内容Ajax Request,但是这个函数在responseText我的页面上冻结了一些 ms。

有人可以告诉我为什么会这样吗?

这是我的功能:

//process Ajax responseText
window.processResponse = function(response) {
    if (!response) return;
    var div = document.createElement("div");
    div.innerHTML = response;
    var divElements = div.getElementsByTagName("*");
    var divChildren = div.children;
    //set unique id for each element and save all ids in array
    var ids = [];
    for (var i = 0; i < divElements.length; i++) {
        var em = divElements[i];
        if (!em.id) {
            var hash = (em.innerHTML || em.outerHTML).toHash();
            var o = 0;
            if (ids.inArray(hash)) em.id = hash + "_" + (++o);
            else em.id = hash;
        }
        ids.push(em.id);
    } //endfor
    for (var i = 0; i < divChildren.length; i++) {
        var root = divChildren[i];
        var documentRoot = document.getElementById(root.id);
        if (documentRoot) {
            if (documentRoot.getAttribute("page") != root.getAttribute("page")) {
                documentRoot.innerHTML = root.innerHTML;
                documentRoot.setAttribute("page", root.getAttribute("page"));
                return;
            }
            var pageHash = div.innerHTML.toHash();
            if (documentRoot.getAttribute("hash") == pageHash) {
                return;
            }
            documentRoot.setAttribute("hash", pageHash);
            var rootElements = root.getElementsByTagName("*");
            var node = null;
            var prevNode = {};
            var parentNode = null;
            var documentNode = null;
            var documentParentNode = null;
            var index = 0;
            var noChange = {};
            while (node = rootElements[index++]) {
                parentNode = node.parentNode;
                if (noChange[parentNode.id]) {
                    continue;
                }
                documentNode = document.getElementById(node.id);
                documentParentNode = document.getElementById(parentNode.id);
                if (!documentNode) {
                    //if element not exists then create new node
                    if (prevNode[parentNode.id]) documentParentNode.insertBefore(node, prevNode[parentNode.id].nextSibling);
                    else documentParentNode.insertBefore(node, documentParentNode.firstChild);
                    documentNode = node;
                    index--;
                } else {
                    //if node exists then check it's content
                    if (!node.children[0] && !documentNode.children[0]) {
                        var nodeHash = (node.innerHTML || node.outerHTML).toHash();
                        var documentHash = (documentNode.innerHTML || documentNode.outerHTML).toHash();
                        if (nodeHash != documentHash) {
                            documentNode.parentNode.insertBefore(node, documentNode.nextSibling);
                            documentNode.parentNode.removeChild(documentNode);
                            documentNode = node;
                            index--;
                        }
                    }
                    //if loaded node has no children then just replace old node with new one
                    else if (!node.children[0]) {
                        documentNode.parentNode.insertBefore(node, documentNode.nextSibling);
                        documentNode.parentNode.removeChild(documentNode);
                        documentNode = node;
                        index--;
                    } else {
                        var nodeHash = (node.innerHTML || node.outerHTML).toHash();
                        var documentHash = (documentNode.innerHTML || documentNode.outerHTML).toHash();
                        if (nodeHash == documentHash) noChange[node.id] = true;
                    }
                }
                //save previous node
                prevNode[parentNode.id] = documentNode;
            } //endwhile
            //remove unneded nodes
            var documentRootElements = documentRoot.getElementsByTagName("*");
            for (var j = 0; j < documentRootElements.length; j++) {
                if (!ids.inArray(documentRootElements[j].id)) {
                    documentRootElements[j].parentNode.removeChild(documentRootElements[j]);
                    j--;
                }
            } //endfor
        }
    } //endfor
};
//generate hashCode from string
String.prototype.toHash = function() {
    var hash = 0,
        i, chr;
    var str = this.clear();
    if (str.length == 0) return hash;
    for (i = 0; i < str.length; i++) {
        chr = str.charCodeAt(i);
        hash = ((hash << 5) - hash) + chr;
        hash = hash & hash;
    }
    return hash.toString();
};
4

1 回答 1

1

好的,所以第一个问题是你有一个巨大的函数,它不断地抓取所有元素,然后在每个迭代级别重新抓取相同的节点。

至少在你这样做之前你没有将 div 附加到 DOM —— 那将是 JS 自杀。

为什么不使用递归进行深度优先遍历,这至少可以节省多次抓取所有子元素的时间(除非您确定这会破坏您的堆栈,在这种情况下,您几乎无能为力使其成为一项快速功能)?

另外:JS是单线程的。如果您一口气完成所有这些操作,那么您的 UI 将完全没有响应,直到您完成所有操作。

走递归路线,如果您将此功能分解为多个步骤,也可以让您恢复 UI。

如果你可以添加一个简单的 10 毫秒 setTimeout(recurseHTML, 10); 在那里(或包含您要发送的任何参数的匿名函数),这将使浏览器有时间完成用户一直在等待执行的任何交互。

这意味着您必须更加努力地考虑如何满足您的“已完成”条件,这意味着您必须等待一段时间才能完成该过程——但可用性胜过这两件事。

于 2012-07-16T19:10:26.470 回答