javascript - Javascript 将一些计算结果一一追加到表行中
问题描述
我正在开发一个简单的 electron / node.js 应用程序,它在本地获取输入信息,进行一些计算并将计算结果显示在表格中
输入:
10s of rows of features info
ID | length | depth |
计算:每个特征计算大约需要几秒钟。
输出:
Some amount of row from input, but with a results column
ID | length | depth | Results
我试图将结果附加到表中以进行呈现,代码如下所示
<table id = 'results-table'>
<th>ID</th><th>length</th><th>depth</th><th>Results</th>
</table>
function getCrackTableValues(){
document.body.style.cursor = 'wait';
var table = document.getElementById('input-table'); //get info from input table
for (var r = 1, n = table.rows.length; r < n; r++) { //skip table head tart from second row
const crackID = table.rows[r].cells[0].innerHTML; //input
var a_m = Number(table.rows[r].cells[1].innerHTML); // input
var c_m = Number(table.rows[r].cells[2].innerHTML); //input
var result = foo(a_m, c_m); //foo just for example, takes seconds for calculation
var newRow = document.getElementById('results-table').insertRow(); //output table
newRow.innerHTML = '<td>'+ crackID+
'</td><td>' + `${a_m.toFixed(1)}` +
'</td><td>' + `${c_m.toFixed(1)}` +
'</td><td>' + `${result.toFixed(1)}` + //append results to output table
'</td>';
}
document.body.style.cursor = 'default';
}
该代码工作正常,但有几个问题。
Q1:我希望一次计算完成后,它会在输出表上显示结果,然后转到下一个条目的计算。因此用户可以看到当前结果,而其余行的计算仍在继续。
目前,在所有计算完成之前,输出表似乎不会显示。
随着每一行的计算继续进行,有什么方法可以让结果表一一增长/显示?
Q2:我试图在计算过程中禁用光标document.body.style.cursor = 'wait';
。并在所有计算完成后重新启用光标。
但似乎这一行是在计算后执行的,它只会禁用光标并闪回。
我当前的实施是否存在任何潜在问题?我的 node.js 是 v12.16.3,在旧的 32 位 windows 7 上。
解决方案
这两个问题的原因是相同的:UI 将没有机会更新,直到它设法逃脱您的非常长时间运行的循环。
您需要更改foo()
为异步函数。你没有显示任何细节,所以我假设它是纯粹的 CPU 计算,没有文件或网络访问点。
我想我首先将循环内容提取到另一个函数中。然后我将循环终止条件放在该新函数的顶部:
function processOneRow(r){
const table = document.getElementById('input-table');
if(r >= table.rows.length){ //All done
document.body.style.cursor = 'default';
return;
}
const crackID = table.rows[r].cells[0].innerHTML;
const a_m = Number(table.rows[r].cells[1].innerHTML);
const c_m = Number(table.rows[r].cells[2].innerHTML);
const result = foo(a_m, c_m);
const newRow = document.getElementById('results-table').insertRow();
newRow.innerHTML = '<td>'+ ...;
setTimeout(processOneRow, 0, r+1)
}
然后你可以通过在第一行调用它来开始它:
function getCrackTableValues(){
document.body.style.cursor = 'wait';
setTimeout(processOneRow, 0, 1)
}
使用setTimeout()
0ms 延迟,给 UI 线程每次更新的时间,然后再调用processOneRow()
输入表的下一行。
顺便说一句:把代码恢复到里面的光标processOneRow()
有点代码味道。如果此代码在库中,我可能会使用before()
/after()
钩子。(然后,您还可以确保在after()
抛出异常时调用该钩子。)
解决此问题的另一种方法是使用工作线程并将foo(a_m, c_m)
计算移到那里。那自然是异步的。除了额外的复杂性之外,其缺点是如果foo()
使用数据,则需要将其保存在该工作线程中,如果在主线程中需要相同的数据,这将变得复杂。但是,否则,对于长时间运行的进程来说,它是一个更好的解决方案。
推荐阅读
- docker - Docker 挂载文件到容器中清除目录
- javascript - 第一个函数完成后执行第二个函数
- vba - Jacobian [vba] 所需方程的导数
- flutter - 为什么我的 TextEditingController 不起作用?
- android - Android 26 只返回一个路径 Context.getExternalFilesDirs()
- r - 如何强制 rmarkdown pdf 输出在新页面中启动目录?
- nginx - SSL 证书无效
- asp.net-core - Html Helper 到 Tag Helper 的转换
- python - 模板继承不起作用 - Django 教程
- c# - 如何将 C# BigInteger 转换为 MySQL DECIMAL(36,18)?