HTML 中承诺循环的记录进度不起作用
Logging progress of loop of promises in HTML is not working
使用下面的代码,我试图记录一系列循环的进度。
但是,如您所见,DOM 中的进度并未顺利记录。许多百分比增量被跳过。
我该如何解决?
;(async () => {
let width = document.getElementById('width')
let numOfImages = 8
let images = Array.from(Array(numOfImages).keys())
let pixelsPerImage = 3600
let totalPixels = numOfImages * pixelsPerImage
let currentLoop = 0
for (let img of images) {
await new Promise((resolve) => {
// this setTimeout is actually an image.onload callback
setTimeout(() => {
let i = 0
while (i < pixelsPerImage) {
;(function(cloop) {
window.requestAnimationFrame(() => {
let prcnt = ((100/totalPixels) * cloop).toFixed(2)
width.innerHTML = prcnt + '%'
width.style.width = prcnt + '%'
})
})(++currentLoop)
i++
}
resolve()
}, 5000)
})
}
await Promise.all(promises)
})()
看起来您正在尝试 运行 8 个并行承诺,但它们 运行 一个接一个。
它是这样的:
创建了 8 个 promise,一个接一个。每个 promise 都会注册一个 5000 毫秒的 setTimeout。
一旦 5000 毫秒结束,将有 8 个回调等待,运行时间将一个接一个地调用它们(JavaScript 是单线程)。
第一个 promise 将执行 3600 次循环,并将写入 console.log
3600 次。然后下一个 promise 回调将在 运行 时间调用,下一个 3600 循环将做同样的事情...直到所有 8 个循环都结束。
你看到很多 console.log
因为你做了 3600*8 次...你没有看到 DOM 变化,因为浏览器只会在执行完成后呈现。
为了看到 dom 变化,您必须“释放”代码的执行,您可以使用 setTimeout(..., 0)
执行此操作以获得下一个即时渲染。甚至更好地使用 requestAnimationFrame
您可能希望每帧都执行最少的操作以使浏览器快速渲染。避免巨大的循环,缓慢的代码。
接下来你可能会遇到的是,进度速度会根据你的CPU而变化,如果你想无论CPU力量都一样,你会想要开始花时间进入考虑,这是一个完全不同的主题:-)
它减慢了整体进度,因为我现在正在等待 HTML 更新完成,然后再进入下一个循环,但 HTML 中显示的进度现在是准确且光滑的。这是一个权衡。
;(async () => {
let width = document.getElementById('width')
let topLoops = 8
let innerLoops = 3600
let totalLoops = topLoops * innerLoops
let currentLoop = 0
let images = Array.from(Array(topLoops).keys())
for (let img of images) {
await new Promise((resolve) => {
// this setTimeout is actually an image.onload callback
setTimeout(async() => {
let i = 0
while (i < innerLoops) {
currentLoop++
await new Promise((resolve) => {
window.requestAnimationFrame(() => {
let prcnt = ((100/totalLoops) * currentLoop).toFixed(2)
width.innerHTML = prcnt + '%'
width.style.width = prcnt + '%'
resolve()
})
})
i++
}
resolve()
}, 5000)
})
}
await Promise.all(promises)
})()
#width {
float:left;
height: 20px;
background: red;
color: black;
padding: 3px;
}
<div id="width"></div>
使用下面的代码,我试图记录一系列循环的进度。
但是,如您所见,DOM 中的进度并未顺利记录。许多百分比增量被跳过。
我该如何解决?
;(async () => {
let width = document.getElementById('width')
let numOfImages = 8
let images = Array.from(Array(numOfImages).keys())
let pixelsPerImage = 3600
let totalPixels = numOfImages * pixelsPerImage
let currentLoop = 0
for (let img of images) {
await new Promise((resolve) => {
// this setTimeout is actually an image.onload callback
setTimeout(() => {
let i = 0
while (i < pixelsPerImage) {
;(function(cloop) {
window.requestAnimationFrame(() => {
let prcnt = ((100/totalPixels) * cloop).toFixed(2)
width.innerHTML = prcnt + '%'
width.style.width = prcnt + '%'
})
})(++currentLoop)
i++
}
resolve()
}, 5000)
})
}
await Promise.all(promises)
})()
看起来您正在尝试 运行 8 个并行承诺,但它们 运行 一个接一个。
它是这样的: 创建了 8 个 promise,一个接一个。每个 promise 都会注册一个 5000 毫秒的 setTimeout。
一旦 5000 毫秒结束,将有 8 个回调等待,运行时间将一个接一个地调用它们(JavaScript 是单线程)。
第一个 promise 将执行 3600 次循环,并将写入 console.log
3600 次。然后下一个 promise 回调将在 运行 时间调用,下一个 3600 循环将做同样的事情...直到所有 8 个循环都结束。
你看到很多 console.log
因为你做了 3600*8 次...你没有看到 DOM 变化,因为浏览器只会在执行完成后呈现。
为了看到 dom 变化,您必须“释放”代码的执行,您可以使用 setTimeout(..., 0)
执行此操作以获得下一个即时渲染。甚至更好地使用 requestAnimationFrame
您可能希望每帧都执行最少的操作以使浏览器快速渲染。避免巨大的循环,缓慢的代码。
接下来你可能会遇到的是,进度速度会根据你的CPU而变化,如果你想无论CPU力量都一样,你会想要开始花时间进入考虑,这是一个完全不同的主题:-)
它减慢了整体进度,因为我现在正在等待 HTML 更新完成,然后再进入下一个循环,但 HTML 中显示的进度现在是准确且光滑的。这是一个权衡。
;(async () => {
let width = document.getElementById('width')
let topLoops = 8
let innerLoops = 3600
let totalLoops = topLoops * innerLoops
let currentLoop = 0
let images = Array.from(Array(topLoops).keys())
for (let img of images) {
await new Promise((resolve) => {
// this setTimeout is actually an image.onload callback
setTimeout(async() => {
let i = 0
while (i < innerLoops) {
currentLoop++
await new Promise((resolve) => {
window.requestAnimationFrame(() => {
let prcnt = ((100/totalLoops) * currentLoop).toFixed(2)
width.innerHTML = prcnt + '%'
width.style.width = prcnt + '%'
resolve()
})
})
i++
}
resolve()
}, 5000)
})
}
await Promise.all(promises)
})()
#width {
float:left;
height: 20px;
background: red;
color: black;
padding: 3px;
}
<div id="width"></div>