Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: layout performance #155

Merged
merged 17 commits into from Apr 20, 2021
Merged

fix: layout performance #155

merged 17 commits into from Apr 20, 2021

Conversation

temper357
Copy link
Contributor

@temper357 temper357 commented Apr 13, 2021

Closes #146

修复之前解决 flex bug 引入的性能问题与有关联的 layout bug:

Flexbox layout 机制

由于 Flexbox 自身渲染机制决定在 performLayout 时最多要进行两次 layout,第一次在不考虑 flex factor(flex-grow/flex-shrink) 的情况下进行 layout 并记录每个 flex item 的 intrinsic content size (计算 flex factor 时使用),第二次根据 flex factor 是否存在及 align-items 是否为 stretch 决定是否要进行二次 layout。

当前优化策略

优化的目标是尽量减少 layout 次数,对于 flow 与 flex layout 的通用策略是:
1. 在主动 layout 时(自身 style change 或者 children markNeedsLayout 时),总是 layout。
2. 在被动 layout 时(自身未发生变化,但是由 sibling 的主动 layout 向上 markNeedsLayout 进而引发从顶向下的 layout 引起),判断根据 style 是否能计算出完整的 size 并且与上一次的 size 比较,如果不相等则 layout,否则不 layout。

性能问题

上面的优化策略在原理上没问题,但是在后续的解决 bug 迭代过程中引入了新的 bug 导致了 break:
1. 在 needsLayout 为 false 时判断当前 size 与 old size 是否相等的逻辑有 bug,导致 width/height 未定义的情况下总是需要 layout,实际应该是相反不应该 layout。此 bug 也是导致上面 issue 性能拖垮的直接原因。
2. 当 flex item 存在 flex factor 时,原来的逻辑是 flex item 的第一次 layout 必须要执行以计算出 intrinsic content size,以便第二次 layout 时计算 flex factor 时使用,由于要进行两次 layout 在节点数量巨大且嵌套层数多的时候 layout 性能下降明显。实际上 intrinsic content size 只在 flex item 标识为 needsLayout 时才需要重新计算。 因此需要在原策略基础上增加第 3 条策略:
在 flex item layout 时缓存 intrinsic content size,后续被动 layout 时可以跳过第一次 layout,如果 flex factor 不存在甚至可以继续跳过第二次 layout。优化后可以做到被动 layout 场景下 layout 次数最小化。

关联 bug

解决了 flex 容器无宽高完全由 children 撑开的场景下的一些渲染 bug:
1. Flex 容器的 align-items 为 stretch 且当前 flex item 的 sibling cross size 变化时,当前 flex item 的 cross size 未同步变化。
2. Flex 容器中 sibling flex item main size 变化且当前 flex item 上存在 flex-grow/flex-shrink 时,当前 flex-item 的 main size 计算不正确。
3. flex item 设置 flex shorthand 时,自身 main size 未撑开并且 flex 容器的 main size 也未撑开。(issue 中的渲染 bug)
4. 重构 layout constraints 计算逻辑,修复 min-width/height max-width/height 与 width/height 同时存在时的宽高计算不正确。

另外,flex-basis 的表现与浏览器不一致的问题,处理比较复杂单独登记 issue 后面解决。

@temper357 temper357 changed the title [WIP] fix: layout performance fix: layout performance Apr 15, 2021
@@ -50,7 +50,7 @@ describe('auto-height', () => {
await snapshot();
});

it("with flex", async () => {
xit("with flex", async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

xit 的原因?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

上面 PR 中有写,flex-basis 为 0 时效果与浏览器不一致,单独列了一个 issue, 原来也只是在 flex direction column 下能跑过,flex direction row 下还是有问题。

@@ -444,7 +444,7 @@ describe('flex-direction', () => {

await snapshot();
});
it("column-overlap-001", async () => {
xit("column-overlap-001", async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

xit的原因?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

同上 flex-basis 0 的问题。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Kraken 在遇到比较复杂的嵌套布局时会卡死
4 participants