Is there a way to create out of DOM elements in Web Worker?

隐身守侯 提交于 2019-11-27 03:49:27

Alright, I did some more research with the information @Bergi provided and found the following discussion on W3C mailing list:

http://w3-org.9356.n7.nabble.com/Limited-DOM-in-Web-Workers-td44284.html

And the excerpt that answers why there is no access to the XML parser or DOM parser in the Web Worker:

You're assuming that none of the DOM implementation code uses any sort of non-DOM objects, ever, or that if it does those objects are fully threadsafe. That's just not not the case, at least in Gecko.

The issue in this case is not the same DOM object being touched on multiple threads. The issue is two DOM objects on different threads both touching some global third object.

For example, the XML parser has to do some things that in Gecko can only be done on the main thread (DTD loading, offhand; there are a few others that I've seen before but don't recall offhand).

There is however also a workaround mentioned, which is using a third-party implementation of the parsers, of which jsdom is an example. With this you even have access to your own separate Document.

Bergi

So is there any way, that I'm not aware of, to create DOM elements, outside the DOM tree, in a Web Worker?

No.

Why not? It seems to me that this can't create concurrency problems, as creating the elements could happen in parallel without problems.

Not for creating them, you're right. But for appending them to the main document - they would need to be sent to a different memory (like it's possible for blobs) so that they're inaccessible from the worker thereafter. However, there's absolutely no Document handling available in WebWorkers.

I create a DOM element for each line as soon as the data arrives (in JSON via ajax). Afterwards I save the elements in an array and I only show the lines that are visible.

Constructing over 500k DOM elements is the heavy task. Try to create DOM elements only for the lines that are visible. To improve performance and showing the first few lines faster, you also might chunk their processing into smaller units and use timeouts in between. See How to stop intense Javascript loop from freezing the browser

You have to understand the nature of a webworker. Programming with threads is hard, especially if you're sharing memory; weird things can happen. JavaScript is not equipped to deal with any kind of thread-like interleaving.

The approach of webworkers is that there is no shared memory. This obviously leads to the conclusion that you can't access the DOM.

There is no direct way to access the DOM through Web Workers. I recently released @cycle/sandbox, it is still WIP, but it proves with the Cycle JS architecture it is fairly straight forward to declare UI behaviour in the Web Worker. The actual DOM is only touched in the main thread, but event listeners, and DOM updates are indirectly declared in the worker, and a synthesized event object is sent when something happens on those listeners. Furthermore it is straight forward to mount these sandboxed Cycle Components side-by-side regular Cycle Components.

http://github.com/aronallen/-cycle-sandbox/

I don't see any reason why you can't construct html strings using web-workers. But I also don't think there would be much of a performance boost.

This isn't related to Web-Workers, but it relates to the problem you're trying to solve. Here are some thing that might help speed things up:

  1. Use DocumentFragments. Add elements to them as the data comes in, and add the fragments to the DOM at an interval (like once a second). This way you don't have to touch the DOM (and incur a redraw) every time a line of text is loaded.

  2. Do loading in the background, and only parse the lines as the user hits the bottom of the scroll area.

According to https://developer.mozilla.org/en-US/docs/Web/Guide/Performance/Using_web_workers there's no access to the DOM from a web worker unfortunately.

You have a couple of anti-patterns in your design:

  1. Creating a DOM object has considerable overhead, and you are creating potentially millions of them at once.
  2. Trying to get a web worker to manage the DOM is exactly what web workers are not for. They do everything else so the DOM event loop stays responsive.

You can use a cursor pattern to scroll through arbitrarily large sets of data.

  1. DOM posts a message to worker with start position and number of lines requested (cursor).
  2. Web worker random accesses logs, posts back the fetched lines (cursor data).
  3. DOM updates an element with the async cursor response event.

This way, the heavy lifting is done by the worker, whose event loop is blocked during the fetch instead of the DOM, resulting in happy non-blocked users marvelling at how smooth all your animations are.

So you can't directly create DOM in a webworker - however, there may be another option to do a fair bit of your processing outside the main thread.

Check out this jsPerf I just created: http://jsperf.com/dom-construction-obj-vs-str

Essentially, you could be emitting POJSO's that have all the same values you get from a DOM, and convert it to DOM objects after receiving the message (this is what you're doing when you get HTML back, after all; POJSOs are just lower overhead, by virtue of not requiring further string processing). In this way you could even do things like emit event listeners and such (by, say, prefixing the event name with '!', and having the value map to some template-supplied view argument).

Meanwhile, without the DOM parser available, you'll need your own thing to convert a template as-needed, or to compile one to a format that's fast.

user316264

No you can't create DOM elements in a web worker, but you can create a function that accepts the post message from that web worker, that does create the DOM elements. I think the deign that your looking for is called array chucking. And you would need to mix that with the web worker design pattern.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!