sam*_*249 10 javascript algorithm performance canvas virtualscroll
我想提出一些理论问题。
假设我有一个无限滚动,实现了如下所述的内容:https : //medium.com/frontend-journeys/how-virtual-infinite-scrolling-works-239f7ee5aa58。没什么好看的,说它是一张数据表,比如说NxN就够了,用户可以向下和向右滚动,就像电子表格一样,它只会显示当前视图中的数据加减一个处理。
现在,我们还假设在该视图中“获取和显示”数据大约需要 10 毫秒,使用如下函数:
get_data(start_col, end_col, start_row, end_row);
Run Code Online (Sandbox Code Playgroud)
当单击滚动条中的某处或执行“轻微滚动”以呈现必要的数据时,这会立即加载。但是,我们还假设对于每个“未完成的获取事件”,呈现必要的视图数据所需的时间加倍(由于内存、gc 和其他一些原因)。因此,如果我以缓慢的故意方式从左到右滚动,我可能会生成 100 多个滚动事件,这些事件会触发数据加载——起初明显延迟为零。获取在 10 毫秒内发生,但很快就开始需要 20 毫秒,然后是 40 毫秒,现在我们有一个明显的延迟,直到加载必要的数据超过一秒。此外,我们不能使用诸如去抖动/延迟之类的东西,
我需要考虑哪些因素以及实现此目的的示例算法是什么样的?这是我希望对数据进行的用户交互示例,假设有一个 10000 x 10000 的电子表格(尽管 Excel 可以一次加载所有数据)——https://gyazo.com/0772f941f43f9d14f884b7afeac9f414。
我认为您不应该在任何滚动事件中发送请求。仅当用户通过此滚动到达滚动的末尾时。
if(e.target.scrollHeight - e.target.offsetHeight === 0) {
// the element reach the end of vertical scroll
}
if(e.target.scrollWidth - e.target.offsetWidth === 0) {
// the element reach the end of horizontal scroll
}
Run Code Online (Sandbox Code Playgroud)
您还可以指定一个宽度,该宽度将定义为足够接近以获取新数据 (ei e.target.scrollHeight - e.target.offsetHeight <= 150)
有些事情是可以做的。我将其视为放置在数据请求过程和用户滚动事件之间的两级中间层。
1.延迟滚动事件处理
你是对的,反跳不是我们在滚动相关问题上的朋友。但有正确的方法可以减少解雇次数。
使用滚动事件处理程序的限制版本,每个固定时间间隔最多调用一次。您可以使用 lodashthrottle 或实现自己的版本 [ 1 ]、[ 2 ]、[ 3 ]。设置 40 - 100 ms 作为间隔值。您还需要设置trailing选项,以便无论计时器间隔如何,都可以处理最后一个滚动事件。
2. 智能数据流
当调用滚动事件处理程序时,应启动数据请求过程。正如您所提到的,每次发生滚动事件时执行此操作(即使我们完成了限制)可能会导致时间滞后。可能有一些常见的策略:1)如果有另一个待处理的请求,则不请求数据;2) 每个时间间隔请求数据不超过一次;3) 取消之前的待处理请求。
第一种和第二种方法只不过是数据流层面的去抖和节流。只需在发起请求之前的一个条件+最后一个额外的请求,就可以用最少的努力来实现反跳。但我相信从用户体验的角度来看,节流阀更合适。在这里您需要提供一些逻辑,并且不要忘记trailing游戏中应该有的选项。
最后一种方法(取消请求)也是用户体验友好的,但不如限制方法那么仔细。无论如何,您都会启动该请求,但如果在此请求之后启动了另一个请求,则丢弃其结果。如果您正在使用 ,您也可以尝试中止请求fetch。
在我看来,最好的选择是结合(2)和(3)策略,因此只有在自上一个请求发起以来经过了某个固定时间间隔时才请求数据,并且如果在之后发起另一个请求,则取消该请求。