- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有大量来自 Excel 的 html 剪贴板数据,大约 250MB(虽然它包含很多格式,所以在实际粘贴时,数据要小得多)。
目前我正在使用以下 DOMParser
,这只是一行代码,一切都发生在幕后:
const doc3 = parser.parseFromString(htmlString, "text/html");
然而,解析这个需要大约 18 秒,并且在此期间页面完全阻塞直到它完成 - 或者,如果卸载到网络 worker ,一个没有任何进展并且只是“等待”18 秒直到最终发生的操作- 我认为这与卡住几乎相同,即使是的,用户可以从字面上与页面进行交互。
test/html
剪贴板中的内容(asci 格式):
https://drive.google.com/file/d/1ZUL2A4Rlk3KPqO4vSSEEGBWuGXj7j5Vh/view?usp=sharing
最佳答案
这里的问题不是 html
文件大小,而是它包含的大量 DOM 节点。对于 html
文件中的 900000 行和 8 列,我们有这些数字:
900000 ( TR elements) * ( 8 ( TD elements) + 8 ( Text nodes)) = ~14 millions of DOM nodes!
我没有设法用 DOMParser
加载它,浏览器选项卡在一段时间后崩溃(FF,Chrome,16GB RAM),尽管看看成功加载时浏览器的行为会很有趣。
无论如何,我遇到了类似的挑战,要在浏览器中处理数百万条记录,我想出的解决方案是一次只为一个屏幕构建表格行。
考虑到 text/html
文件的结构,接下来的方法可能是:
- use
FileReader
to load html file as raw text- grab rows, save them as text array, remove them from output
- parse resulting output, insert the table and style into DOM
- use a view / paging, render the current batch of rows on paging/scroll or search
- attach events for mouse/keyboard control
html
上完成的,对于
text
仅搜索您可以取消注释“//text: text.match...”行,尽管在这种情况下文件解析时间会增加一点。
let tbody, style;
let rows = [], view = [], viewSize = 20, page = 0, time = 0;
const load = fRead => {
console.timeEnd('FILE LOAD');
console.time('GRAB ROWS');
let thead, trows = '', table = fRead.result
.replace(/<tr[^]+<\/tr>/i, text => (trows += text) && '');
console.timeEnd('GRAB ROWS');
console.time('PARSE/INSERT TABLE & STYLE');
const html = document.createElement('div');
html.innerHTML = table;
table = html.querySelector('table');
if (!table || !trows) {
setInfo('NO DATA FOUND');
return;
}
if (style = html.querySelector('style'))
document.head.appendChild(style);
table.textContent = '';
el('viewport').appendChild(table);
console.timeEnd('PARSE/INSERT TABLE & STYLE');
console.time('PREPARE ROWS ARRAY');
rows = trows.split('<tr').slice(1).map(text => ({
html: '<tr' + text, text,
//text: text.match(/>.*<\/td>/gi).map(s => s.slice(1, -5)).join(' '),
}));
console.timeEnd('PREPARE ROWS ARRAY');
console.time('RENDER TABLE');
table.appendChild(thead = document.createElement('thead'));
table.appendChild(tbody = document.createElement('tbody'));
thead.innerHTML = rows[0].html;
view = rows = rows.slice(1);
renew();
console.timeEnd('RENDER TABLE');
console.timeEnd('INIT');
};
const reset = info => {
el('info').textContent = info ?? '';
el('viewport').textContent = '';
style?.remove();
style = null;
tbody = null;
view = rows = [];
};
const pages = () => Math.ceil(view.length / viewSize) - 1;
const renew = () => {
if (!tbody)
return;
console.time('RENDER VIEW');
const i = page * viewSize;
tbody.innerHTML = view.slice(i, i + viewSize)
.map(row => row.html).join('');
console.timeEnd('RENDER VIEW');
setInfo(`
rows total: ${rows.length},
rows match: ${view.length},
pages: ${pages()}, page: ${page}
`);
};
const gotoPage = num => {
el('page').value = page = Math.max(0, Math.min(pages(), num));
renew();
};
const fileInput = () => {
reset('LOADING...');
const fRead = new FileReader();
fRead.onload = load.bind(null, fRead);
console.time('INIT');
console.time('FILE LOAD');
fRead.readAsText(el('file').files[0]);
};
const fileReset = () => {
reset();
el('file').files = new DataTransfer().files;
};
const setInfo = text => el('info').innerHTML = text;
const setView = e => {
let value = +e.target.value;
value = Number.isNaN(value * 0) ? 20 : value;
e.target.value = viewSize = Math.max(1, Math.min(value, 100));
renew();
};
const setPage = e => {
const page = +e.target.value;
gotoPage(Number.isNaN(page * 0) ? 0 : page);
};
const setFilter = e => {
const filter = e.target.value;
let match;
try {
match = new RegExp(filter);
} catch (e) {
setInfo(e);
return;
}
view = rows.filter(row => match.test(row.text));
page = 0;
renew();
};
const keys = {'PageUp': -1, 'PageDown': 1};
const scroll = e => {
const dir = e.key ? keys[e.key] ?? 0 : Math.sign(-e.deltaY);
if (!dir)
return;
e.preventDefault();
gotoPage(page += dir);
};
const el = id => document.getElementById(id);
el('file').addEventListener('input', fileInput);
el('reset').addEventListener('click', fileReset);
el('view').addEventListener('input', setView);
el('page').addEventListener('input', setPage);
el('filter').addEventListener('input', setFilter);
el('viewport').addEventListener('keydown', scroll);
el('viewport').addEventListener('wheel', scroll);
div {
display: flex;
flex: 1;
align-items: center;
white-space: nowrap;
}
thead td,
tbody tr td:first-child {
background: grey;
color: white;
}
td { padding: 0 .5em; }
#menu > * { margin: 0 .25em; }
#file { min-width: 16em; }
#view, #page { width: 8em; }
#filter { flex: 1; }
#info { padding: .5em; color: red; }
<div id="menu">
<span>FILE:</span>
<input id="file" type="file" accept="text/html">
<button id="reset">RESET</button>
<span>VIEW:</span><input id="view" type="number" value="20">
<span>PAGE:</span><input id="page" type="number" value="0">
<span>FILTER:</span><input id="filter">
</div>
<div id="info"></div>
<div id="viewport" tabindex="0"></div>
FILE LOAD: 352.57421875 ms
GRAB ROWS: 700.1943359375 ms
PARSE/INSERT TABLE & STYLE: 0.78125 ms
PREPARE ROWS ARRAY: 755.763916015625 ms
RENDER VIEW: 0.926025390625 ms
RENDER TABLE: 4.317138671875 ms
INIT: 1814.19287109375 ms
RENDER VIEW: 5.275146484375 ms
RENDER VIEW: 4.6318359375 ms
~1.8 s
,即比 OP 指定的
DOMParser
所花费的时间低一个数量级,随后的行渲染几乎是即时的:
~5 ms
关于javascript - 用于大型 html 的 DOMParser,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66645084/
我正在解析一个包含 a b ..... z 我可以通过以下方式获取项目标签 document.getElementsByTag("items"); 但问题是我无
我正在为 Google Chrome 创建一个插件。我尝试解析以下 xml: 9938 Ikoku Meiro no Croisée Cro
我正在尝试获取我使用 DOMParser 解析的元素的样式属性。 2 console.logs 虽然是空的。知道为什么会这样吗? .xl496 { color:#33669
在将 AJAX 加载的 html 内容注入(inject) DOM 之前,我使用 DOMParser 对其进行操作。 caniuse声明当前的支持很好,但不会回溯到 IE 版本 10 之前仅提供部分支
https://developer.mozilla.org/en-US/docs/Web/API/DOMParser#DOMParser_HTML_extension 看起来 DOMParser 使用
我遇到了一个非常不寻常的问题。如果有必要,为了更好地了解整体情况,请参阅我的上一篇文章,Unable to retrieve a sub-NodeList from a NodeList in Jav
在控制台中执行此操作时,为什么会出现解析错误? TR = ' Hello '; parser = new DOMParser() xmlDocument = _parser
我有一些 HTML 字符串。使用 domparser 更新一些值,现在我需要返回带有更新值的 HTML 字符串格式...Bcoz document.write 仅接受字符串。 查看示例补丁, cons
我正在将 html 从 api 转换为 dom 元素,以便我可以解析 xml 内容。内容示例: var html = 'George Romero, the highly influential au
jQuery 从字符串创建 DOM 元素的首选 native 方法之一是使用新的 DOMParser 类。此示例摘自 MDN : var parser = new DOMParser(); var d
我在使用 DomParser 时遇到了一些奇怪的行为。似乎如果第一个元素是 TEMPLATE,它就会被忽略。 查看下面的输出: printTags('', 'text/html'); document
当我使用 document.createElement 创建脚本元素时并将其附加到 document.head , JavaScript 执行成功: var el = document.createE
为什么以下 DOMParser 的使用导致 HTML 与用作输入的 HTML 不同?它删除了 DOCTYPE 和顶级元素之间的空格,删除了文档元素和 head 之间的空格。 , 并在 之前添加换行符
如果您查看 MDN 中的 DOMParser 示例: var parser = new DOMParser(); var doc = parser.parseFromString(stringCont
我在 Ajax 中加载 HTML,用 DOMParser 解析它并把所有 childNodes将文档主体转换为文档片段。 当我将片段添加到当前文档的正文中时,标签未执行。 我四处摸索,发现如果我用新的
我有一个使用 DOMParser 解析 XML 的方法,如下所示: this.parseXmlString = function(xmlDocStr) { var xmlDoc; va
// html data loaded from [http://example.org/some/path] let htmlSource = ` ... ... `; const dom =
我有大量来自 Excel 的 html 剪贴板数据,大约 250MB(虽然它包含很多格式,所以在实际粘贴时,数据要小得多)。 目前我正在使用以下 DOMParser ,这只是一行代码,一切都发生在幕后
我正在使用以下代码将字符串解析为 DOM: var doc = new DOMParser().parseFromString(string, 'text/xml'); 在哪里 string类似于 c
DOMParser 有一个奇怪的行为。当我使用“text/xml”作为参数时,我得到了我的对象,并且每次我使用子节点(如parentNodes)时,子节点本身就是一个DOM对象。但是,当我使用“tex
我是一名优秀的程序员,十分优秀!