Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: fullstack-star/homework-browser1
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: master
Choose a base ref
...
head repository: qyingkou/homework-browser-stage
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: master
Choose a head ref
Able to merge. These branches can be automatically merged.
  • 4 commits
  • 7 files changed
  • 1 contributor

Commits on Jun 30, 2019

  1. Unverified

    This commit is not signed, but one or more authors requires that any commit attributed to them is signed.
    Copy the full SHA
    93d4d6b View commit details
  2. 增加说明

    qyingkou committed Jun 30, 2019

    Unverified

    This commit is not signed, but one or more authors requires that any commit attributed to them is signed.
    Copy the full SHA
    ae530ac View commit details
  3. add screenshot

    qyingkou committed Jun 30, 2019
    Copy the full SHA
    6ede60c View commit details
  4. 改进文字表述

    qyingkou committed Jun 30, 2019
    Copy the full SHA
    8d6bb5c View commit details
Showing with 641 additions and 1 deletion.
  1. +27 −0 .editorconfig
  2. +22 −1 README.md
  3. +43 −0 index.css
  4. +50 −0 index.html
  5. +150 −0 index.js
  6. +349 −0 normalize.css
  7. BIN screenshot.png
27 changes: 27 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# EditorConfig is awesome: https://EditorConfig.org
# top-most EditorConfig file
root = true

[*]
end_of_line = lf
indent_style = tab
tab_width = 2
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.json]
insert_final_newline = ignore

[**.{min,bundle}.js]
indent_style = ignore
insert_final_newline = ignore

[Makefile]
indent_style = tab

[*.bat]
indent_style = tab

[*.md]
trim_trailing_whitespace = false
23 changes: 22 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,22 @@
# homework-browser1
# homework-browser-stage

## 不同关键渲染路径的耗时实验

以下测试单元的共同目标是“将1000个列表项随机在x轴移动”。我们考察以下策略会对性能造成影响:

`在【每次迭代都重新计算布局】中`:每次迭代都把原布局失效掉,同时重新计算布局。
`在【仅重新计算一次布局】中`:每次迭代都把原布局失效掉,但只重新计算一次布局。
`在【仅重绘】中`:每次迭代都把原绘画失效掉,同时重新绘制。
`在【仅重新合成】中`:每次迭代都把原合成失效掉,同时重新合成。


考察不同的关键渲染路径下,会对性能和耗时产生多大的影响。
我们验证了哪些cssdom接口会使原计算结果失效(重新计算的前提条件),哪些cssdom接口会强制让渲染引擎立即开始计算(性能消耗)。
得出的结论是,尽量forced reflow在路径的末端,越往上越影响性能。


## 参考资料:
- 哪些属性会使哪些关键渲染计算失效
https://csstriggers.com/
- 哪些属性会让强制渲染引擎立即开始计算
https://kellegous.com/j/2013/01/26/layout-performance/
43 changes: 43 additions & 0 deletions index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
.container {
padding: 20px;
}
.container .sum{
white-space: pre-line;
font-size: 14px;
line-height: 1.5;
color: 666;
}
.operate {
padding: 10px;
}
.operate .operate_item {
margin-bottom: 10px;
}
.operate button {
padding: 10px 20px;
font-size: 14px;
line-height: 1;
border: 1px solid #666;
border-radius: 4px;
}
.operate span {
margin-left: 20px;
font-size: 14px;
line-height: 1.5;
vertical-align: middle;
}
#list ul,
#list li {
list-style: none;
}
#list ul li {
position: relative;
margin: 5px 0;
padding: 10px;
width: 400px;
transform: translateX(0px);
background-color: #efefef;
font-size: 12px;
line-height: 1.5;
color: #666;
}
50 changes: 50 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>浏览器渲染原理 - layout\paint\composite成本测试</title>
<link rel="stylesheet" href="./normalize.css">
<link rel="stylesheet" href="./index.css">
</head>

<body>
<div class="container">
<h2 class="ttl">不同关键渲染路径的耗时实验</h2>
<pre class="sum">
以下测试单元的共同目标是“将1000个列表项随机在x轴移动”。我们考察以下策略会对性能造成影响:
在【每次迭代都重新计算布局】中:每次迭代都把原布局失效掉,同时重新计算布局。
在【仅重新计算一次布局】中:每次迭代都把原布局失效掉,但只重新计算一次布局。
在【仅重绘】中:每次迭代都把原绘画失效掉,同时重新绘制。
在【仅重新合成】中:每次迭代都把原合成失效掉,同时重新合成。
</pre>
<div class="operate">
<div class="operate_item j-init">
<button>初始化节点</button>
<span>--</span>
</div>
<div class="operate_item j-multipleLayout">
<button>每次迭代都重新计算布局(layout update)</button>
<span>--</span>
</div>
<div class="operate_item j-singleLayout">
<button>仅重新计算一次布局(layout update)</button>
<span>--</span>
</div>
<div class="operate_item j-paint">
<button>仅重绘(paint upate)</button>
<span>--</span>
</div>
<div class="operate_item j-composite">
<button>仅重新合成(composite update)</button>
<span>--</span>
</div>
</div>
<div id="list"></div>
</div>
<script src="./index.js"></script>
</body>

</html>
150 changes: 150 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
var elm_list = document.getElementById("list"),
elm_multipleLayout = document.getElementsByClassName("j-multipleLayout")[0],
elm_singleLayout = document.getElementsByClassName("j-singleLayout")[0],
elm_paint = document.getElementsByClassName("j-paint")[0],
elm_composite = document.getElementsByClassName("j-composite")[0],
elm_init = document.getElementsByClassName("j-init")[0];

/* 初始化界面 */
function init() {
var num = 1000,
node_ul = document.createElement("ul");
while (num > 0) {
var node_li = document.createElement("li");
node_li.innerText = `line ${num}`;
node_li.style.transform = "translateX(0px)";
node_ul.insertAdjacentElement("afterBegin", node_li);
num--;
}
// 操作文档
elm_list.appendChild(node_ul);
Array.prototype.forEach.call(elm_list.getElementsByTagName("li"), function(
item
) {
translateX(item);
});

// 监听 - 多次重新布局按钮
elm_multipleLayout.addEventListener("click", function(e) {
var tg = e.target,
timestamp = null,
elm_txt = this.getElementsByTagName("span")[0];
if (tg.tagName !== "BUTTON") return;

elm_txt.innerText = "";
timestamp = performance.now();
multipleLayout();
timestamp -= performance.now();
elm_txt.innerText = `${Math.abs(Math.round(timestamp))}ms`;
tg.disabled = "disabled";
});

// 监听 - 一次重新布局按钮
elm_singleLayout.addEventListener("click", function(e) {
var tg = e.target,
timestamp = null,
elm_txt = this.getElementsByTagName("span")[0];
if (tg.tagName !== "BUTTON") return;

elm_txt.innerText = "";
timestamp = performance.now();
singleLayout();
timestamp -= performance.now();
elm_txt.innerText = `${Math.abs(Math.round(timestamp))}ms`;
tg.disabled = "disabled";
});

// 监听 - 重绘按钮
elm_paint.addEventListener("click", function(e) {
var tg = e.target,
timestamp = null,
elm_txt = this.getElementsByTagName("span")[0];
if (tg.tagName !== "BUTTON") return;

elm_txt.innerText = "";
timestamp = performance.now();
paint();
timestamp -= performance.now();
elm_txt.innerText = `${Math.abs(Math.round(timestamp))}ms`;
tg.disabled = "disabled";
});

// 监听 - 重新合成按钮
elm_composite.addEventListener("click", function(e) {
var tg = e.target,
timestamp = null,
elm_txt = this.getElementsByTagName("span")[0];
if (tg.tagName !== "BUTTON") return;

elm_txt.innerText = "";
timestamp = performance.now();
composite();
timestamp -= performance.now();
elm_txt.innerText = `${Math.abs(Math.round(timestamp))}ms`;
tg.disabled = "disabled";
});
}

/* 多次重新布局 */
function multipleLayout() {
var elms_list_li = document.getElementById("list").getElementsByTagName("li");
Array.prototype.forEach.call(elms_list_li, function(item, index) {
item.style.opacity = 0.9;
if (!item.offsetHeight) console.log("");
item.style = null;
translateX(item);
});
}

/* 一次重新布局 */
function singleLayout() {
var elm_list = document.getElementById("list");
var elms_list_li = elm_list.getElementsByTagName("li");

Array.prototype.forEach.call(elms_list_li, function(item, index) {
item.style.opacity = 0.9;
item.style = null;
translateX(item);
});
if (!elm_list.offsetHeight) console.log("");
}

/* 重绘 */
function paint() {
var elms_list_li = document.getElementById("list").getElementsByTagName("li");
Array.prototype.forEach.call(elms_list_li, function(item, index) {
item.style.visibility = "none";
item.style = null;
translateX(item);
});
}

/* 重新合成 */
function composite() {
var elms_list_li = document.getElementById("list").getElementsByTagName("li");
Array.prototype.forEach.call(elms_list_li, function(item, index) {
translateX(item);
});
}

/* 公共业务 - 移动 */
function translateX(elm) {
elm.style.transform = `
translateX(${Math.round(Math.random() * 100)}px)
`;
}

/* 监听 - 初始化按钮 */
elm_init.addEventListener("click", function(e) {
var tg = e.target,
timestamp = null,
elm_txt = this.getElementsByTagName("span")[0];
if (tg.tagName !== "BUTTON") return;
elm_txt.innerText = "";
timestamp = performance.now();
init();
timestamp -= performance.now();
elm_txt.innerText = `${Math.abs(Math.round(timestamp))}ms`;
this.getElementsByTagName("button")[0].disabled = "disabled";
});
elm_init.getElementsByTagName("button")[0].click();
Loading