渲染管理

渲染管理系统会告知渲染程序何时重新渲染块。它可确保在修改块时(例如,设置字段值或添加输入),块的形状也会更新以匹配。

何时关注

如果您处于以下情况,则需要与此系统互动:

  • 向 Blockly 中添加了用于修改块形状的方法。
  • 向 Blockly 中添加了一些方法,这些方法依赖于块的相关更新后的大小或定位信息。

运作方式

  1. 自动加入队列。每次修改块时,Blockly 都会将该块的渲染“加入队列”。以下是一些将渲染加入队列的修改示例:

    • 设置字段的值
    • 添加或移除输入源
    • 连接或取消关联子块
  2. 创建资源集。当一个块加入队列时,渲染管理系统会将该块及其所有父块添加到一组需要重新渲染的块中。

  3. 请求回电。然后,渲染管理系统使用 requestAnimationFrame 请求回调。浏览器会在绘制当前帧之前调用此回调。

  4. 重新渲染该集(作为树)。调用 requestAnimationFrame 回调时,渲染管理系统会渲染该组中从叶块到根块的每个块。这可确保子块在父块渲染之前具有准确的大小信息,以便父块可以围绕其子块进行拉伸。

运作方式

等到当前帧即将绘制之前再重新渲染块,这让渲染管理系统能够删除重复的渲染请求。如果块始终立即渲染,则同一块可能在一行中被渲染多次,这是不必要的。而是批量处理渲染请求,并且每个已更改的块只在其状态最终确定之后才会在帧结束时绘制一次。对渲染操作进行去重可让 Blockly 的效率更高。

例如,在另外两个队列之间插入一个块会进行 11 个渲染,但实际只会出现 3 个块(每个块对应一个)。这是 3.6 倍的性能提升。

使用方法

您通常不必关注渲染管理系统,因为它会在您修改块时自动运行。但在少数情况下,您必须直接与它互动。

队列渲染

如果您要向 Blockly 中添加会更新块形状的新方法,则需要调用 BlockSvg.prototype.queueRender 来将渲染块加入队列。

等待渲染完成

如果您要向 Blockly 中添加一种需要更新块大小或定位信息的新方法,则应等待 renderManagement.finishQueuedRenders() promise。此 promise 会在所有已加入队列的渲染完成后立即解析;如果没有已加入队列的渲染,则会立即解析。

import * as renderManagement from './renderManagement.js';

function async myNewMethod() {
  block.somethingThatModifiesTheShape();
  // Await the promise.
  await renderManagement.finishQueuedRenders();
  myThingThatReliesOnPositioningInfo();
}

立即触发已加入队列的渲染

如果您要向 Blockly 中添加一种新方法,该方法需要更新某块的大小或定位信息,并且无法等到下一帧完成任何渲染,则可以调用 renderManagement.triggerQueuedRenders 强制立即进行所有已加入队列的渲染。

import * as renderManagement from './renderManagement.js';

function async myNewMethod() {
  block.somethingThatModifiesTheShape();
  // Trigger an immediate render.
  renderManagement.triggerQueuedRenders();
  myThingThatReliesOnPositioningInfo();
}

一般来说,您不想这样做,因为它的性能较差。只有在延迟会导致糟糕的用户体验的情况下,才有必要这样做。例如,插入标记需要定位信息,因此插入标记必须为用户提供即时反馈,以便它们触发立即渲染。

出于向后兼容性方面的原因,它在核心中还有几个位置会触发立即渲染。我们计划在 v11 中移除这些库。