使用JavaScript高效执行多个DOM更新 [英] Executing multiple DOM updates with JavaScript efficiently

查看:90
本文介绍了使用JavaScript高效执行多个DOM更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个包含数百个div元素的HTML / JS网站。应该一次快速更新几十个这些元素(每秒最多250次)(即它们应该一次更新,而不需要浏览器通过逐个执行更新来执行不必要的工作一)。什么是性能最高的方法(最小化CPU负载和内存消耗),以支持现代浏览器使用纯JavaScript或简单库实现此目的(不使用 React 或类似的库,要求我修改DOM处理之外的代码)?我正在寻找类似这样的东西(imaginaryLibrary是我不知道的库,我正在寻找):

I have a HTML/JS website with several hundreds of div elements. A few dozens of these elements should be updated in a rapid fashion (up to 250 times per second) at one time (i.e. they should all be updated at once, without having the browser to perform unnecessary work by performing the updates one-by-one). What is the most performant way (minimizing the CPU load and memory consumption) to do this supporting modern browsers to achieve this with pure JavaScript or with a simple library (without using React or a similar library requiring me to modify the code beyond the DOM handling)? I'm looking for something like this (where imaginaryLibrary is the library unknown to me, which I'm looking for):

var i, element;
for(i = 0; i < 20; i++){
    element = document.getElementById('el' + i);
    imaginaryLibrary.collectDomUpdate(element, cssClass, 'updatedCssClass');
}
//executes DOM updates collected in loop before and applies the DOM updates in one reflow
imaginaryLibrary.applyUpdates();

要更新的元素的父元素包含数千个元素,不应更新。

The parent element of the elements to update contains thousands of elements, which should not be updated.

推荐答案

您并不是真正具体了解您正在做什么,所以我们能做的最好的事情就是给您一般的建议关于一堆相关领域。

You aren't real specific about exactly what you're doing so about the best we can do here is to give you general advice about a bunch of relevant areas.

DOM修改

你没有完全填写你想要做的所有细节,但是在优化你的代码工作方式时需要考虑以下几点:

You don't quite fill in all the details of what you're trying to do, but here are a bunch of things to take into consideration when optimizing how your code works:


  1. 回流已排队。浏览器已尝试最小化回流,因此如果您在一个连续的Javascript中进行四次dom修改,浏览器将等待那段Javascript完成运行,然后进行一次回流和一次重绘。

  1. Reflows are already queued. The browser already attempts to minimize reflows so if you do four dom modifications in one sequential piece of Javascript, the browser will wait for that piece of Javascript to finish running and then do one reflow and one repaint.

请求某些属性可以立即触发重排。您希望避免上述规则的例外情况。例如,如果您请求某些DOM属性需要正确布局以准确报告属性值,并且先前的修改中存在待处理的布局,则浏览器可以在返回您请求的属性之前同步地重新布局文档。这些类型的属性通常涉及屏幕位置和其他属性,这些属性显然会受到文档布局的影响。如果您想了解更多详细信息,有很多关于此主题的文章。在许多情况下,您的代码无论如何都不会使用这些属性,但如果是这样,通常的解决方法是在对DOM进行任何更改之前先请求所有需要的属性。

Requesting certain properties can trigger an immediate reflow. There are exceptions to the above rule that you want to make sure you avoid. For example if you request certain DOM properties that require proper layout for the property value to be accurately reported and there is a pending layout from a prior modification, then the browser may relayout the document synchronously before returning the property you requested. These type of properties usually involve things like screen position and other properties that would obviously be affected by the layout of the document. There are many articles on this topic if you want to find further details. In many cases your code won't be using these properties anyway, but if so, the usual workaround is to request all the needed properties first before making any changes to the DOM.

一次批量处理所有DOM更改。最糟糕的事情是进行DOM更改,使用计时器等待几毫秒,进行另一个DOM更改,等待几毫秒使用计时器等因为你将进行DOM更改,重排,重绘,DOM更改,重排,重新绘制等...相反,请确保您在一个同步的Javascript中同时执行所有挂起的DOM更改。然后,这将允许浏览器对重排进行排队并重新绘制,并在完成所有DOM更改后再执行一次。如果您想更好地了解批处理,您将折叠对同一元素的修改,以便仅使用最终值处理一次。因此,如果elementA首先被赋予新值3,然后在同一批次中被赋予值4,则在处理该批数据时,您希望跳过3并仅处理4。

Batch up all your DOM changes at once. The worst thing to do is to make a DOM change, wait a few ms with a timer, make another DOM change, wait a few ms with a timer and so on because you will have DOM change, reflow, repaint, DOM change, reflow, repaint, etc... Instead, make sure you're doing all pending DOM changes at once in one synchronous piece of Javascript. This will then allow the browser to queue the reflow and repaint and do it only once after you've made all your DOM changes. If you want to get even smarter about the batching, you will collapse modifications to the same element so that it is only processed once with the final value. So, if elementA was first given a new value of 3 and then later in the same batch was given a value of 4, when processing the batch of data, you want to skip the 3 and just process the 4.

有时可以优化DOM修改。您没有提供有关如何修改DOM的任何细节,但是如果要修改复杂对象(比如添加许多表行或更改大量表格单元格),有时最好创建一组当前未插入DOM的DOM元素,对它们进行所有修改,然后通过一个操作,将它们插入DOM。这是因为修改当前插入DOM中的DOM元素会强制浏览器确定哪些其他DOM元素受此更改影响,因此它可以排队相应的重排或重新绘制。但是,在将一个较大的对象插入DOM的最后一步之前,修改屏幕外DOM元素不必进行任何工作。这里没有有用的通用规则,因为您如何利用此优化完全取决于您正在进行的DOM修改。我们可以帮助您解决这个问题,但只有当我们看到您拥有的HTML以及您正在进行的更改时才会有所帮助。

DOM modifications can sometimes be optimized. You don't give us any specifics on how you are modifying the DOM, but if you are modifying complex objects (like adding many table rows or changing lots of table cells), then it is sometimes better to create a set of DOM elements that are not currently inserted in the DOM, make all your modifications to them and then with one operation, insert them into the DOM. This is because modifying DOM elements that are currently inserted in the DOM forces the browser to figure out which other DOM elements are affected by this change so it can queue the appropriate reflows or repaints. But modifying off-screen DOM elements does not have to do any of that work until the one last step where one larger object is inserted into the DOM. There is no useful generic rules here because how you take advantage of this optimization depends entirely upon what DOM modifications you are doing. We could help you with this, but only when we could see both the HTML you have and exactly what changes you're making to it.

更新时间

现在,至于事情的时间安排,你提到每秒最多250次。对于用户可见的东西,这种速度很快(每次操作4ms)。如果你这样做,你的浏览器基本上将不断回流和重新绘制,只是偶尔暂停来处理其他用户事件。由于没有用户能够在4ms,8ms和12ms之后实际看到发生的事情,所以通常不需要在屏幕上更新状态。

Now, as for the timing of things, you mentioned up to 250 times per second. That's kind of fast (4ms per operation) for a user viewable thing. If you do that, your browser is basically going to be constantly reflowing and repainting with only occasional pauses to process other user events. Since no user can actually see something happen at 4ms, 8ms and 12ms from now, there's really no need to update status on screen that often.

所以,如果你确实有快速或经常发生的变化,你可能想要通过将它们累积到本地数据结构中来批量处理,然后每次更新屏幕100-500ms左右。你必须试验你可以使用的长间隔,而不是真正注意到任何延迟。

So, if you really have changes coming in that fast or often, you may want to batch them by accumulating them into a local data structure and then just updating the screen every 100-500ms or so. You'd have to experiment with what the long interval you could use and not really notice any delay.

批处理更新有多种实施策略。我能想到的最简单的方法是,如果你的修改总是在不断地进行流式处理,那么只需将修改放入本地数组中,然后只需为你的更新间隔设置一个间隔计时器来检查数组以及是否有任何内容,它将数组中的所有项目处理为DOM更新。

There are several implementation strategies for batching the updates. The simplest I can think of if your modifications are always streaming in constantly is to just put the modifications into a local array as they come in and then just have an interval timer set for your update interval that checks the array and if there's anything in it, it process all the items in the array into a DOM update.

从服务器获取更改

您没有提到浏览器Javascript如何获取新数据。通常有两个选项,重复Ajax请求或创建webSocket,服务器可以随时直接向您发送数据。

You don't mention how the browser Javascript is getting the new data. There are generally two options, repeated Ajax requests or create a webSocket and the server can directly send you data at any time.

如果您的更新定期且间隔很短, webSocket连接显然是最有效的。这是一个持续连接,只要服务器有新数据要发送,服务器就可以向每个客户端发送新数据。

If your updates are regularly and shortly spaced, the webSocket connection is clearly the most efficient. It's one constant connection and the server can just send each client new data whenever the server has new data to send.

如果你要用Ajax进行轮询,那么我强烈建议你延长轮询时间间隔。非常短的轮询间隔将真正加载您的服务器并在客户端上吃电池。

If you're going to be polling with Ajax, then I'd strongly suggest you lengthen out the polling interval. A very short polling interval will both really load your server and eat the battery on the client.

电池

如果这个应用程序打算在电池供电的设备上长时间运行,那么从任何服务器实时获取稳定的数据流(例如,如你所提到的每隔几毫秒)吃电池是因为无线电(WiFi或Cellular)几乎一直处于活动状态,CPU也会运行很多。

If this app is intended to run for long periods of time on a battery powered device, then getting a steady stream of data real-time (e.g. every few ms like you mentioned) from any server is going to eat battery because the radio (WiFi or Cellular) will be active nearly all the time and the CPU is going to be running a lot too.

这篇关于使用JavaScript高效执行多个DOM更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆