如何正确优化每次连接长字符串的长循环?
How to properly optimize a long for loop that concats a long string everytime?
我正在做一个小型学习项目,它从 API 中获取硬币列表,然后构建一个充满 bootstrap 卡片的页面,长度为从 API。
在开发过程中,我只使用了 100 个第一个硬币以避免长时间等待,但现在我已经完成了,当我尝试了整个 3900 多个硬币时,它花费了不切实际的长时间。
我很确定我添加字符串的方式是问题的根源,我会添加我的代码,我相信这一切都会更有意义。
我尝试构建整个字符串然后附加它 - 还是很慢。
我每次都尝试更改它的 innerHTML 然后附加它(附加在 for 循环内),但它只是覆盖所有旧硬币并仅附加最后一个。
我想要它做的实际上是分别附加每个框并在合理的时间内完成,现在需要 30 多分钟才能完成,这显然不好。
我添加的当前版本的代码是一个需要很长时间但最终做对了的代码(虽然它在 for 循环中只有 50 次迭代,所以如果你现在尝试它不会卡住,它需要超过 3900 次迭代)
function homeStart(coins: any[]): void {
var divcreate = document.createElement("div");
for (var i = 0; i < 50; i++) {
// console.log(coins[i]);
// ******This is where the string addup starts
divcreate.innerHTML += `
<div class="card text-dark bg-dark m-auto makeinline"
id="${coins[i].id}${i}" style="max-width: 18rem;">
<div class="card-header">
<div class="flexalign">
<span class="coinsymbol"
id="${coins[i].symbol.toUpperCase() +
"a1"}">${coins[i].symbol.toUpperCase()}
</span>
<label class="switch">
<input type="checkbox"
id="${coins[i].id}${coins[i].symbol}"
onchange="selectedCoinUpdate(this,'${coins[i].symbol}')">
<span class="slider round"></span>
</label>
</div>
</div>
<div class="card-body">
<div class="">
<h5 class="card-title coinname">${coins[i].name}</h5>
<button type="button" class="btn btn-secondary" data-
toggle="collapse" href="#collapseIdentity${i}" role="button"
aria-expanded="false" aria-
controls="collapseIdentity${i}"
onclick="moreInfo('${coins[i].id}')">More info</button>
</div>
<div class="collapse" id="collapseIdentity${i}">
<div class="card-body" id="${coins[i].id}">
</div>
</div>
</div>
</div>`;
}
// ******This is where the string addup ends
$("#pagecont").append(divcreate);
}
为了快速加载 DOM 个元素,你可以看到这个 link ->
尽可能快地获取东西后,它仍然可能太慢并可能导致浏览器冻结/崩溃。
长运行在JS中同步操作会锁死UI,.
为了防止这种情况,您可以将长 运行 sync
操作转换为 async
操作,这有利于 UI 一些呼吸 space.然后您可以创建加载指示器等。
下面是一个非常简单的示例,我正在执行一个大约需要 100 毫秒的同步操作,并执行 100 次。这将加起来总共 10 秒,如果您在不使用 async
的情况下这样做,那将不会是一个很好的用户体验。
为了证明 UI 没有被锁定,我只是让 Loading 指示灯闪烁粉红色,当然你可以做一个旋转的圆圈等。完成后它还会控制台日志 all done
,..
希望这个小例子对长时间的 运行 sync
操作有所帮助。
ps:我一直相信 async/await
是为了做下一个滴答,对我来说虽然在没有 sleep(0)
的情况下进行循环仍然会导致 UI锁定 10 秒。
const loaddiv = document.querySelector(".loading");
var i = setInterval(() => {
loaddiv.classList.toggle("loading");
}, 300);
const sleep = (time) => new Promise((resolve) => setTimeout(resolve, time));
async function blockUI() {
let now = new Date().getTime();
const desiredTime = now + 100;
while (now < desiredTime) {
now = new Date().getTime();
}
await sleep(0); //give the UI some breathing space
}
async function longLoop() {
for (let l = 0; l < 100; l += 1)
await blockUI();
clearInterval(i);
console.log("all done");
}
longLoop();
.loading {
background-color: pink;
}
<div class="loading">
Loading.
</div>
正如 Keith 所说,您可以在多个任务中转换您独特的同步操作,并 运行 以异步方式转换这些任务(在他的示例中为 setTimeout)。
用这种方式代替一次大操作可以提高 UI 性能,但效果不是很好,因为您触摸了 DOM。
触摸 DOM 很慢,因为浏览器可能有很多操作要做(绘画、回流等)。因此,最好让浏览器在他触摸 DOM 并使其 DOM 工作的最佳时间执行您的任务。
为此,浏览器主要有两种方法供您使用:
- requestAnimationFrame :通常用于执行动画,但最好是让浏览器执行 DOM 操作。
- requestIdleCallback : 执行后台和低优先级工作
所以这是一个结合这两种方法的例子:https://codesandbox.io/s/7jz3yjow0q
这里有一些关于网络性能的重要资源:
我正在做一个小型学习项目,它从 API 中获取硬币列表,然后构建一个充满 bootstrap 卡片的页面,长度为从 API。 在开发过程中,我只使用了 100 个第一个硬币以避免长时间等待,但现在我已经完成了,当我尝试了整个 3900 多个硬币时,它花费了不切实际的长时间。
我很确定我添加字符串的方式是问题的根源,我会添加我的代码,我相信这一切都会更有意义。
我尝试构建整个字符串然后附加它 - 还是很慢。 我每次都尝试更改它的 innerHTML 然后附加它(附加在 for 循环内),但它只是覆盖所有旧硬币并仅附加最后一个。
我想要它做的实际上是分别附加每个框并在合理的时间内完成,现在需要 30 多分钟才能完成,这显然不好。
我添加的当前版本的代码是一个需要很长时间但最终做对了的代码(虽然它在 for 循环中只有 50 次迭代,所以如果你现在尝试它不会卡住,它需要超过 3900 次迭代)
function homeStart(coins: any[]): void {
var divcreate = document.createElement("div");
for (var i = 0; i < 50; i++) {
// console.log(coins[i]);
// ******This is where the string addup starts
divcreate.innerHTML += `
<div class="card text-dark bg-dark m-auto makeinline"
id="${coins[i].id}${i}" style="max-width: 18rem;">
<div class="card-header">
<div class="flexalign">
<span class="coinsymbol"
id="${coins[i].symbol.toUpperCase() +
"a1"}">${coins[i].symbol.toUpperCase()}
</span>
<label class="switch">
<input type="checkbox"
id="${coins[i].id}${coins[i].symbol}"
onchange="selectedCoinUpdate(this,'${coins[i].symbol}')">
<span class="slider round"></span>
</label>
</div>
</div>
<div class="card-body">
<div class="">
<h5 class="card-title coinname">${coins[i].name}</h5>
<button type="button" class="btn btn-secondary" data-
toggle="collapse" href="#collapseIdentity${i}" role="button"
aria-expanded="false" aria-
controls="collapseIdentity${i}"
onclick="moreInfo('${coins[i].id}')">More info</button>
</div>
<div class="collapse" id="collapseIdentity${i}">
<div class="card-body" id="${coins[i].id}">
</div>
</div>
</div>
</div>`;
}
// ******This is where the string addup ends
$("#pagecont").append(divcreate);
}
为了快速加载 DOM 个元素,你可以看到这个 link ->
尽可能快地获取东西后,它仍然可能太慢并可能导致浏览器冻结/崩溃。
长运行在JS中同步操作会锁死UI,.
为了防止这种情况,您可以将长 运行 sync
操作转换为 async
操作,这有利于 UI 一些呼吸 space.然后您可以创建加载指示器等。
下面是一个非常简单的示例,我正在执行一个大约需要 100 毫秒的同步操作,并执行 100 次。这将加起来总共 10 秒,如果您在不使用 async
的情况下这样做,那将不会是一个很好的用户体验。
为了证明 UI 没有被锁定,我只是让 Loading 指示灯闪烁粉红色,当然你可以做一个旋转的圆圈等。完成后它还会控制台日志 all done
,..
希望这个小例子对长时间的 运行 sync
操作有所帮助。
ps:我一直相信 async/await
是为了做下一个滴答,对我来说虽然在没有 sleep(0)
的情况下进行循环仍然会导致 UI锁定 10 秒。
const loaddiv = document.querySelector(".loading");
var i = setInterval(() => {
loaddiv.classList.toggle("loading");
}, 300);
const sleep = (time) => new Promise((resolve) => setTimeout(resolve, time));
async function blockUI() {
let now = new Date().getTime();
const desiredTime = now + 100;
while (now < desiredTime) {
now = new Date().getTime();
}
await sleep(0); //give the UI some breathing space
}
async function longLoop() {
for (let l = 0; l < 100; l += 1)
await blockUI();
clearInterval(i);
console.log("all done");
}
longLoop();
.loading {
background-color: pink;
}
<div class="loading">
Loading.
</div>
正如 Keith 所说,您可以在多个任务中转换您独特的同步操作,并 运行 以异步方式转换这些任务(在他的示例中为 setTimeout)。
用这种方式代替一次大操作可以提高 UI 性能,但效果不是很好,因为您触摸了 DOM。
触摸 DOM 很慢,因为浏览器可能有很多操作要做(绘画、回流等)。因此,最好让浏览器在他触摸 DOM 并使其 DOM 工作的最佳时间执行您的任务。
为此,浏览器主要有两种方法供您使用:
- requestAnimationFrame :通常用于执行动画,但最好是让浏览器执行 DOM 操作。
- requestIdleCallback : 执行后台和低优先级工作
所以这是一个结合这两种方法的例子:https://codesandbox.io/s/7jz3yjow0q
这里有一些关于网络性能的重要资源: