Commit f76d59ef76

Pierre Guilleminot <pierre@jow.fr>
2020-04-12 23:13:57
improve search perf: batching dom list mutations
1 parent 8e9e126
Changed files (1)
lib
std
special
docs
lib/std/special/docs/main.js
@@ -256,13 +256,15 @@
                 if (fnObj.combined === undefined) fnObj.combined = allCompTimeFnCallsResult(calls);
                 if (fnObj.combined != null) renderContainer(fnObj.combined);
 
-                resizeDomList(domListFnExamples, calls.length, '<li></li>');
+                var domListFnExamplesFragment = createDomListFragment(calls.length, '<li></li>');
 
                 for (var callI = 0; callI < calls.length; callI += 1) {
-                    var liDom = domListFnExamples.children[callI];
+                    var liDom = domListFnExamplesFragment.children[callI];
                     liDom.innerHTML = getCallHtml(fnDecl, calls[callI]);
                 }
 
+                domListFnExamples.innerHTML = "";
+                domListFnExamples.appendChild(domListFnExamplesFragment);
                 domFnExamples.classList.remove("hidden");
             } else if (instantiations != null) {
                 // TODO
@@ -303,7 +305,7 @@
             return;
         }
 
-        resizeDomList(domListParams, docCount, '<div></div>');
+        var domListParamsFragment = createDomListFragment(docCount, '<div></div>');
         var domIndex = 0;
 
         for (var i = 0; i < fields.length; i += 1) {
@@ -312,7 +314,7 @@
             if (fieldNode.docs == null) {
                 continue;
             }
-            var divDom = domListParams.children[domIndex];
+            var divDom = domListParamsFragment.children[domIndex];
             domIndex += 1;
             var argTypeIndex = typeObj.args[i];
 
@@ -333,12 +335,15 @@
             }
             divDom.innerHTML = html;
         }
+
+        domListParams.innerHTML = "";
+        domListParams.appendChild(domListParamsFragment);
         domSectParams.classList.remove("hidden");
     }
 
     function renderNav() {
         var len = curNav.pkgNames.length + curNav.declNames.length;
-        resizeDomList(domListNav, len, '<li><a href="#"></a></li>');
+        var domListNavFragment = createDomListFragment(len, '<li><a href="#"></a></li>');
         var list = [];
         var hrefPkgNames = [];
         var hrefDeclNames = [];
@@ -358,7 +363,7 @@
         }
 
         for (var i = 0; i < list.length; i += 1) {
-            var liDom = domListNav.children[i];
+            var liDom = domListNavFragment.children[i];
             var aDom = liDom.children[0];
             aDom.textContent = list[i].name;
             aDom.setAttribute('href', list[i].link);
@@ -369,6 +374,8 @@
             }
         }
 
+        domListNav.innerHTML = "";
+        domListNav.appendChild(domListNavFragment);
         domSectNav.classList.remove("hidden");
     }
 
@@ -401,9 +408,9 @@
         });
 
         if (list.length !== 0) {
-            resizeDomList(domListPkgs, list.length, '<li><a href="#"></a></li>');
+            var domListPkgsFragment = createDomListFragment(list.length, '<li><a href="#"></a></li>');
             for (var i = 0; i < list.length; i += 1) {
-                var liDom = domListPkgs.children[i];
+                var liDom = domListPkgsFragment.children[i];
                 var aDom = liDom.children[0];
                 aDom.textContent = list[i].name;
                 aDom.setAttribute('href', navLinkPkg(list[i].pkg));
@@ -414,6 +421,8 @@
                 }
             }
 
+            domListPkgs.innerHTML = "";
+            domListPkgs.appendChild(domListPkgsFragment);
             domSectPkgs.classList.remove("hidden");
         }
     }
@@ -454,29 +463,14 @@
         return navLink(curNav.pkgNames, declNamesCopy);
     }
 
-    function resizeDomListDl(dlDom, desiredLen) {
-        // add the missing dom entries
-        var i, ev;
-        for (i = dlDom.childElementCount / 2; i < desiredLen; i += 1) {
-            dlDom.insertAdjacentHTML('beforeend', '<dt></dt><dd></dd>');
-        }
-        // remove extra dom entries
-        while (desiredLen < dlDom.childElementCount / 2) {
-            dlDom.removeChild(dlDom.lastChild);
-            dlDom.removeChild(dlDom.lastChild);
-        }
-    }
-
-    function resizeDomList(listDom, desiredLen, templateHtml) {
-        // add the missing dom entries
-        var i, ev;
-        for (i = listDom.childElementCount; i < desiredLen; i += 1) {
-            listDom.insertAdjacentHTML('beforeend', templateHtml);
-        }
-        // remove extra dom entries
-        while (desiredLen < listDom.childElementCount) {
-            listDom.removeChild(listDom.lastChild);
+    function createDomListFragment(desiredLen, templateHtml) {
+        var templateHtmlContent = "";
+        for (var i = 0; i < desiredLen; i++) {
+            templateHtmlContent += templateHtml;
         }
+        var domTemplate = document.createElement("template");
+        domTemplate.innerHTML = templateHtmlContent;
+        return domTemplate.content;
     }
 
     function typeIndexName(typeIndex, wantHtml, wantLink, fnDecl, linkFnNameDecl) {
@@ -831,10 +825,10 @@
                 return operatorCompare(a.err.name.toLowerCase(), b.err.name.toLowerCase());
             });
 
-            resizeDomListDl(domListFnErrors, errorList.length);
+            var domListFnErrorsFragment = createDomListFragment(errorList.length, "<dt></dt><dd></dd>");
             for (var i = 0; i < errorList.length; i += 1) {
-                var nameTdDom = domListFnErrors.children[i * 2 + 0];
-                var descTdDom = domListFnErrors.children[i * 2 + 1];
+                var nameTdDom = domListFnErrorsFragment.children[i * 2 + 0];
+                var descTdDom = domListFnErrorsFragment.children[i * 2 + 1];
                 nameTdDom.textContent = errorList[i].err.name;
                 var docs = errorList[i].docs;
                 if (docs != null) {
@@ -843,6 +837,8 @@
                     descTdDom.textContent = "";
                 }
             }
+            domListFnErrors.innerHTML = "";
+            domListFnErrors.appendChild(domListFnErrorsFragment);
             domTableFnErrors.classList.remove("hidden");
         }
         domSectFnErrors.classList.remove("hidden");
@@ -1022,45 +1018,51 @@
         }
 
         if (typesList.length !== 0) {
-            resizeDomList(domListTypes, typesList.length, '<li><a href="#"></a></li>');
+            var domListTypesFragment = createDomListFragment(typesList.length, '<li><a href="#"></a></li>');
             for (var i = 0; i < typesList.length; i += 1) {
-                var liDom = domListTypes.children[i];
+                var liDom = domListTypesFragment.children[i];
                 var aDom = liDom.children[0];
                 var decl = typesList[i];
                 aDom.textContent = decl.name;
                 aDom.setAttribute('href', navLinkDecl(decl.name));
             }
+            domListTypes.innerHTML = "";
+            domListTypes.appendChild(domListTypesFragment);
             domSectTypes.classList.remove("hidden");
         }
         if (namespacesList.length !== 0) {
-            resizeDomList(domListNamespaces, namespacesList.length, '<li><a href="#"></a></li>');
+            var domListNamespacesFragment = createDomListFragment(namespacesList.length, '<li><a href="#"></a></li>');
             for (var i = 0; i < namespacesList.length; i += 1) {
-                var liDom = domListNamespaces.children[i];
+                var liDom = domListNamespacesFragment.children[i];
                 var aDom = liDom.children[0];
                 var decl = namespacesList[i];
                 aDom.textContent = decl.name;
                 aDom.setAttribute('href', navLinkDecl(decl.name));
             }
+            domListNamespaces.innerHTML = "";
+            domListNamespaces.appendChild(domListNamespacesFragment);
             domSectNamespaces.classList.remove("hidden");
         }
 
         if (errSetsList.length !== 0) {
-            resizeDomList(domListErrSets, errSetsList.length, '<li><a href="#"></a></li>');
+            var domListErrSetsFragment = createDomListFragment(errSetsList.length, '<li><a href="#"></a></li>');
             for (var i = 0; i < errSetsList.length; i += 1) {
-                var liDom = domListErrSets.children[i];
+                var liDom = domListErrSetsFragment.children[i];
                 var aDom = liDom.children[0];
                 var decl = errSetsList[i];
                 aDom.textContent = decl.name;
                 aDom.setAttribute('href', navLinkDecl(decl.name));
             }
+            domListErrSets.innerHTML = "";
+            domListErrSets.appendChild(domListErrSetsFragment);
             domSectErrSets.classList.remove("hidden");
         }
 
         if (fnsList.length !== 0) {
-            resizeDomList(domListFns, fnsList.length, '<tr><td></td><td></td></tr>');
+            var domListFnsFragment = createDomListFragment(fnsList.length, '<tr><td></td><td></td></tr>');
             for (var i = 0; i < fnsList.length; i += 1) {
                 var decl = fnsList[i];
-                var trDom = domListFns.children[i];
+                var trDom = domListFnsFragment.children[i];
 
                 var tdFnCode = trDom.children[0];
                 var tdDesc = trDom.children[1];
@@ -1074,17 +1076,19 @@
                     tdDesc.textContent = "";
                 }
             }
+            domListFns.innerHTML = "";
+            domListFns.appendChild(domListFnsFragment);
             domSectFns.classList.remove("hidden");
         }
 
         if (container.fields != null && container.fields.length !== 0) {
-            resizeDomList(domListFields, container.fields.length, '<div></div>');
+            var domListFieldsFragment = createDomListFragment(container.fields.length, '<div></div>');
 
             var containerNode = zigAnalysis.astNodes[container.src];
             for (var i = 0; i < container.fields.length; i += 1) {
                 var field = container.fields[i];
                 var fieldNode = zigAnalysis.astNodes[containerNode.fields[i]];
-                var divDom = domListFields.children[i];
+                var divDom = domListFieldsFragment.children[i];
 
                 var html = '<div class="mobile-scroll-container"><pre class="scroll-item">' + escapeHtml(fieldNode.name);
 
@@ -1107,15 +1111,17 @@
                 }
                 divDom.innerHTML = html;
             }
+            domListFields.innerHTML = "";
+            domListFields.appendChild(domListFieldsFragment);
             domSectFields.classList.remove("hidden");
         }
 
         if (varsList.length !== 0) {
-            resizeDomList(domListGlobalVars, varsList.length,
+            var domListGlobalVarsFragment = createDomListFragment(varsList.length,
                 '<tr><td><a href="#"></a></td><td></td><td></td></tr>');
             for (var i = 0; i < varsList.length; i += 1) {
                 var decl = varsList[i];
-                var trDom = domListGlobalVars.children[i];
+                var trDom = domListGlobalVarsFragment.children[i];
 
                 var tdName = trDom.children[0];
                 var tdNameA = tdName.children[0];
@@ -1134,15 +1140,17 @@
                     tdDesc.textContent = "";
                 }
             }
+            domListGlobalVars.innerHTML = "";
+            domListGlobalVars.appendChild(domListGlobalVarsFragment);
             domSectGlobalVars.classList.remove("hidden");
         }
 
         if (valsList.length !== 0) {
-            resizeDomList(domListValues, valsList.length,
+            var domListValuesFragment = createDomListFragment(valsList.length,
                 '<tr><td><a href="#"></a></td><td></td><td></td></tr>');
             for (var i = 0; i < valsList.length; i += 1) {
                 var decl = valsList[i];
-                var trDom = domListValues.children[i];
+                var trDom = domListValuesFragment.children[i];
 
                 var tdName = trDom.children[0];
                 var tdNameA = tdName.children[0];
@@ -1161,6 +1169,8 @@
                     tdDesc.textContent = "";
                 }
             }
+            domListValues.innerHTML = "";
+            domListValues.appendChild(domListValuesFragment);
             domSectValues.classList.remove("hidden");
         }
     }
@@ -1768,7 +1778,7 @@
         if (ev.ctrlKey) name = "Ctrl+" + name;
         return name;
     }
-    
+
     function onWindowKeyDown(ev) {
         switch (getKeyString(ev)) {
             case "Esc":
@@ -1809,7 +1819,7 @@
 
     function startAsyncSearch() {
         clearAsyncSearch();
-        searchTimer = setTimeout(startSearch, 100);
+        searchTimer = setTimeout(startSearch, 10);
     }
     function startSearch() {
         clearAsyncSearch();
@@ -1881,25 +1891,27 @@
         }
 
         if (matchedItems.length !== 0) {
-            resizeDomList(domListSearchResults, matchedItems.length, '<li><a href="#"></a></li>');
-
             matchedItems.sort(function(a, b) {
                 var cmp = operatorCompare(b.points, a.points);
                 if (cmp != 0) return cmp;
                 return operatorCompare(a.decl.name, b.decl.name);
             });
 
+            var domListSearchResultsFragment = createDomListFragment(matchedItems.length, '<li><a href="#"></a></li>');
             for (var i = 0; i < matchedItems.length; i += 1) {
-                var liDom = domListSearchResults.children[i];
+                var liDom = domListSearchResultsFragment.children[i];
                 var aDom = liDom.children[0];
                 var match = matchedItems[i];
                 var lastPkgName = match.path.pkgNames[match.path.pkgNames.length - 1];
                 aDom.textContent = lastPkgName + "." + match.path.declNames.join('.');
                 aDom.setAttribute('href', navLink(match.path.pkgNames, match.path.declNames));
             }
-            renderSearchCursor();
 
+            domListSearchResults.innerHTML = "";
+            domListSearchResults.appendChild(domListSearchResultsFragment);
             domSectSearchResults.classList.remove("hidden");
+
+            renderSearchCursor();
         } else {
             domSectSearchNoResults.classList.remove("hidden");
         }