0

を使用してウェブサイトのコンテンツを更新する大きな関数を作成しましたAjax Requestが、ページで動作する関数がresponseText数ミリ秒フリーズします。

なぜこれが起こるのかについて誰かが私にヒントを与えることができますか?

ここに私の機能があります:

//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の自殺になります。

再帰を使用した深さ優先探索では、少なくともすべての子要素を複数回取得する時間を節約できます(スタックが破壊されることが確実でない限り、実行できることはほとんどありません)。それを1つのスピーディーな機能にするために)?

また、JSはシングルスレッドです。これらすべてを一度に噛み砕くと、最後までやり遂げるまでUIが完全に応答しなくなります。

この関数を複数のステップに分割した場合、再帰的なルートをたどると、UIを元に戻すこともできます。

単純な10msのsetTimeout(recurseHTML、10);を追加できる場合。そこで(または送信したいパラメーターをラップする無名関数)、ユーザーが実行するのを待っていた対話を完了するための時間をブラウザーに与えます。

これは、「終了した」条件がどのように満たされるかについてもう少し考えなければならないことを意味し、プロセスが終了するまでもう少し待つ必要があることを意味しますが、ユーザビリティはこれらの両方に勝ります。

于 2012-07-16T19:10:26.470 に答える