Fin*_*ers 2 javascript asynchronous
我目前正在开发一个基于 html 的小型项目,其中我在 javascript 中进行了一些长时间运行的计算。我不擅长 javascript,所以我想在这里找到解决方案。基本上我的长时间运行的代码看起来像这样:
let simulation = new Simulation(system,iterations,step_size,callback_fn);
simulation.run();
Run Code Online (Sandbox Code Playgroud)
simulation.run-function 看起来像这样:
run() {
...
for(let i = 0; i < this.steps; i++){
...
this.callback(i+1);
}
}
Run Code Online (Sandbox Code Playgroud)
通常该steps变量约为 100 万。我的计划是添加一个显示进度的进度条。
HTML:
<div class="progress mt-5">
<div id="simulation-progress" class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" style="width: 0%"></div>
</div>
Run Code Online (Sandbox Code Playgroud)
现在我的计划是使用我正在模拟的回调函数来更新我的进度条:
(async () => {
const iterations = 1000000;
const step_size = 1;
simulation_progress.setAttribute('style', `width:0%`);
setTimeout(function(){
let simulation = new Simulation(
system,
iterations,
step_size,
e => {
if(e % 100000 === 0){
simulation_progress.setAttribute('style', `width:${Math.round(100 * e / iterations)}%`);
console.log(e, Math.round(100 * e / iterations))
}
});
simulation.run();
}, 1);
})();
Run Code Online (Sandbox Code Playgroud)
基本上我知道大约 100000 步大约等于 1 秒。每当我的回调返回的步骤是 100000 ( ) 的倍数时steps % 100000 === 0),我都会尝试更新进度条。遗憾的是,这似乎不起作用。所发生的情况是,进度条不会更改,直到模拟完成其 1M 步骤。之后1M步,直接跳到100%。
有人知道是什么原因导致这种行为吗?它是否与更新该异步块内的进度条有关?
我很高兴能得到任何帮助
根据您想要添加的复杂程度,有两种方法可以使其发挥作用。
这是“正确”的解决方案。繁重的工作被外包给 webworker.js 文件,因此 UI 和进度条不会同时冻结。
简单的例子:
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<title>Async Progress Bar Example</title>
</head>
<body>
<progress id="progressBar" value="0" max="100"></progress>
<script src="main.js"></script>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)
// main.js
const worker = new Worker('webworker.js');
worker.onmessage = function(e) {
const progressBar = document.querySelector('#progressBar');
progressBar.value = e.data;
}
async function asyncFunction() {
// simulate a long running task
for (let i = 0; i < 100; i++) {
await new Promise(resolve => setTimeout(resolve, 50));
worker.postMessage(i);
}
}
asyncFunction();
Run Code Online (Sandbox Code Playgroud)
// webworker.js
onmessage = function(e) {
postMessage(e.data + 1);
}
Run Code Online (Sandbox Code Playgroud)
如果您希望使其尽可能简单(例如在一个文件/脚本中)并且您不关心 UI 冻结而只是希望进度条正确更新,请考虑此解决方案。
简单的例子:
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<title>Async Progress Bar Example</title>
</head>
<body>
<progress id="progressBar" value="0" max="100"></progress>
<script src="main.js"></script>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)
// main.js
let progress = 0;
const progressBar = document.querySelector('#progressBar');
async function asyncFunction() {
// simulate a long running task
for (let i = 0; i < 100; i++) {
await new Promise(resolve => setTimeout(resolve, 50));
progress++;
}
}
setInterval(() => {
progressBar.value = progress;
}, 0);
asyncFunction();
Run Code Online (Sandbox Code Playgroud)
请注意,0 毫秒的间隔应该足以更新进度条。就我而言,它工作得很好。此外,用户界面并没有完全冻结,但浏览器每次迭代都会响应滚动或类似的操作。它有点滞后,但对于我的用例来说已经足够了。您还可以将其与灰屏覆盖层结合起来,这样在计算准备就绪之前,用户就不会做任何事情。