上下文 我有一个Web应用程序来处理和显示巨大的日志文件。它们通常只有大约10万行,但它可以达到400万行或更多。为了能够滚动浏览该日志文件(用户启动和通过JavaScript)并过滤具有良好性能的行,我会在数据到达时为每一行创建一个DOM元素(通过ajax以JSON形式)。我发现这对性能更好,然后在后端构建HTML。然后我将元素保存在一个数组中,我只显示可见的行。
对于最大100k行,这只需要几秒钟,但对于500k行(不包括下载),任何更多需要花费一分钟。我想进一步提高性能,所以我尝试使用HTML5 Web Workers。现在的问题是我无法在Web Worker中创建元素,甚至不能在DOM之外创建元素。所以我最终只在Web Workers中进行了json到HTML的转换,并将结果发送到主线程。它在那里创建并存储在一个数组中。不幸的是,这使性能恶化,现在需要至少30秒。
问题:那么在Web工作者中,在DOM树之外创建DOM元素有什么办法,我不知道吗?如果没有,为什么不呢?在我看来,这不会产生并发问题,因为创建元素可以并行发生而没有问题。
答案 0 :(得分:16)
好吧,我用@Bergi提供的信息做了一些研究,并在W3C邮件列表上找到了以下讨论:
http://w3-org.9356.n7.nabble.com/Limited-DOM-in-Web-Workers-td44284.html
摘录解释了为什么Web Worker中无法访问XML解析器或DOM解析器的原因:
您假设没有任何DOM实现代码使用任何排序 非DOM对象,或者如果它完全是那些对象 线程安全的。事实并非如此,至少在Gecko。
此案例中的问题与触摸的DOM对象不同 多线程。问题是不同线程上的两个DOM对象 都触及了一些全球第三个对象。
例如,XML解析器必须做一些Gecko可以做的事情 只能在主线程上完成(DTD加载,offhand;有一个 我之前见过的其他人很少,但不要随便回忆。
然而,还提到了一种解决方法,它使用解析器的第三方实现,其中jsdom就是一个例子。有了这个,您甚至可以访问自己的单独文档。
答案 1 :(得分:11)
在Web工作者中,在DOM树之外创建DOM元素有什么方法,我不知道吗?
没有
为什么不呢?在我看来,这不会产生并发问题,因为创建元素可以并行发生而没有问题。
不是为了创造它们,你是对的。但是为了将它们附加到主document
- 它们需要被发送到不同的内存(就像blob一样),以便之后工作人员无法访问它们。但是,there's absolutely no Document handling available in WebWorkers。
一旦数据到达,我就为每一行创建一个DOM元素(通过ajax以JSON形式)。然后我将元素保存在一个数组中,我只显示可见的行。
构建超过500k的DOM元素是一项艰巨的任务。尝试仅为可见的行创建DOM元素。为了提高性能并更快地显示前几行,您还可以将其处理分成更小的单元并在其间使用超时。见How to stop intense Javascript loop from freezing the browser
答案 2 :(得分:4)
您必须了解网络工作者的性质。用线程编程 hard ,特别是如果你共享内存;可能会发生奇怪的事情。 JavaScript没有能够处理任何类似线程的交错。
网络工作者的方法是没有共享内存。这显然会导致您无法访问DOM。
答案 3 :(得分:4)
没有通过Web Workers访问DOM的直接方法。 我最近发布了@cycle / sandbox,它仍然是WIP,但它证明了使用Cycle JS架构,在Web Worker中声明UI行为是相当直接的。实际DOM仅在主线程中触及,但事件侦听器和DOM更新在worker中间接声明,并且在这些侦听器上发生某些事件时发送合成事件对象。此外,可以直接安装这些沙盒循环组件并排定期循环组件。
答案 4 :(得分:2)
我没有看到任何可以使用网络工作者构建html字符串的原因。但我也不认为会有很大的提升。
这与Web-Workers无关,但它与您尝试解决的问题有关。以下是一些可能有助于加快速度的事情:
使用DocumentFragments。在数据进入时向它们添加元素,并以一定间隔(例如每秒一次)将片段添加到DOM。这样,每次加载一行文本时,您都不必触摸DOM(并进行重绘)。
在后台加载,只在用户点击滚动区底部时解析这些行。
答案 5 :(得分:1)
根据https://developer.mozilla.org/en-US/docs/Web/Guide/Performance/Using_web_workers,不幸的是,网络工作者无法访问DOM。
答案 6 :(得分:1)
您的设计中有几种反模式:
您可以使用光标模式滚动任意大的数据集。
通过这种方式,繁重的工作由工作人员完成,工作人员在获取期间阻止事件循环而不是DOM,从而使快乐的非阻塞用户惊叹于所有动画的流畅程度。
答案 7 :(得分:0)
所以你不能在网络工作者中直接创建DOM - 但是,在主线程之外可能还有另一种方法可以进行相当多的处理。
查看我刚创建的这个jsPerf:http://jsperf.com/dom-construction-obj-vs-str
基本上,你可以发出POJSO,它们具有从DOM获得的所有相同值,并在收到消息后将其转换为DOM对象(这是你在做的时候正在做的事情)毕竟,HTML回来;由于不需要进一步的字符串处理,POJSO只是更低的开销。通过这种方式,您甚至可以执行诸如发出事件侦听器之类的事情(例如,使用'!'为事件名称添加前缀,并将值映射到模板提供的某些视图参数)。
同时,如果没有可用的DOM解析器,您需要自己的东西来根据需要转换模板,或者将其编译为快速的格式。
答案 8 :(得分:0)
不,您不能在Web worker中创建DOM元素,但您可以创建一个接受来自该Web worker的post消息的函数,UIApplication.registerUserNotificationSettings
创建DOM元素。我认为你所寻找的设计被称为阵列吸盘。您需要将其与Web worker设计模式混合使用。