亲爱的Javascript Guru&#39>:
我有以下要求:
例如:
function process_array(batch_size) {
var da_len = data_array.length;
var idx = 0;
function process_batch() {
var idx_end = Math.min(da_len, idx + batch_size);
while (idx < idx_end) {
// do the voodoo we need to do
}
}
// This loop kills the browser ...
while (idx < da_len) {
setTimeout(process_batch, 10);
// Show some progress (no luck) ...
show_progress(idx);
}
}
// Process array ...
process_array(1000);
// Continue with next task ...
// BUT NOT UNTIL WE HAVE FINISHED PROCESSING THE ARRAY!!!
由于我是javascript的新手,我发现一切都是在一个线程上完成的,因此,需要在处理和更新UI方面获得一些创意。我找到了一些使用递归setTimeout调用的例子,(一个关键的区别是我必须等到数组完全处理后再继续),但我似乎无法按上述方式工作。
另外 - 我需要一个纯粹的&#34; javascript解决方案 - 没有第三方库或使用Web工作者(不完全支持)。
任何(和所有)指导都将不胜感激。
提前致谢。
答案 0 :(得分:1)
答案 1 :(得分:1)
在JavaScript中,在HTML页面中执行脚本时,页面将变为无响应,直到脚本完成。这是因为JavaScript是单线程。
您可以考虑在后台运行的JavaScript中使用Web工作器,而不影响其他脚本,而不会影响页面的性能。
在这种情况下,用户可以继续在UI中做任何他想做的事。
您可以发送和接收来自网络工作者的消息。
答案 2 :(得分:0)
因此,递归的魔力之一就是考虑你需要传递的东西,以使其有效。
在JS(和其他功能语言)中经常涉及函数。
function processBatch (remaining, processed, batchSize,
transform, onComplete, onProgress) {
if (!remaining.length) {
return onComplete(processed);
}
const batch = remaining.slice(0, batchSize);
const tail = remaining.slice(batchSize);
const totalProcessed = processed.concat(batch.map(transform));
return scheduleBatch(tail, totalProcessed, batchSize,
transform, onComplete, onProgress);
}
function scheduleBatch (remaining, processed, batchSize,
transform, onComplete, onProgress) {
onProgress(processed, remaining, batchSize);
setTimeout(() => processBatch(remaining, processed, batchSize,
transform, onComplete, onProgress));
}
const noop = () => {};
const identity = x => x;
function processArray (array, batchSize, transform, onComplete, onProgress) {
scheduleBatch(
array,
[],
batchSize,
transform || identity,
onComplete || noop,
onProgress || noop
);
}
这可以极其简化,而现实是我在这里只是有点乐趣,但是如果你遵循这条路径,你应该在一个封闭的系统中看到递归,该系统适用于任意对象,任意对象,任意数组长度,完成时任意代码执行,以及每个批处理完成并安排下一次运行时。
说实话,您甚至可以通过更改3行代码来替换自定义调度程序,然后您可以记录您想要的任何内容......
const numbers = [1, 2, 3, 4, 5, 6];
const batchSize = 2;
const showWhenDone = numbers => console.log(`Done with: ${numbers}`);
const showProgress = (processed, remaining) =>
`${processed.length} done; ${remaining.length} to go`;
const quintuple = x => x * 5;
processArray(
numbers,
batchSize,
quintuple,
showWhenDone,
showProgress
);
// 0 done; 6 to go
// 2 done; 4 to go
// 4 done; 2 to go
// Done with: 5, 10, 15, 20, 25, 30
过度破坏?哦,是的。但值得熟悉这些概念,如果你要花一些时间用这种语言。
答案 3 :(得分:0)
谢谢大家的意见和建议。
以下是我确定的代码。该代码适用于任何任务(在我的情况下,处理数组),并在需要时为浏览器提供更新UI的时间。
“do_task”函数通过setInterval启动一个匿名函数,该函数在两个步骤之间交替 - 批量处理数组并显示进度,这一直持续到数组中的所有元素都被处理完毕。
function do_task() {
const k_task_process_array = 1;
const k_task_show_progress = 2;
var working = false;
var task_step = k_task_process_array;
var batch_size = 1000;
var idx = 0;
var idx_end = 0;
var da_len = data_array.length;
// Start the task ...
var task_id = setInterval(function () {
if (!working) {
working = true;
switch (task_step) {
case k_task_process_array:
idx_end = Math.min( idx + batch_size, da_len );
while (idx < idx_end) {
// do the voodoo we need to do ...
}
idx++;
}
task_step = k_task_show_progress;
working = false;
break;
default:
// Show progress here ...
// Continue processing array ...
task_step = k_task_process_array;
working = false;
}
// Check if done ...
if (idx >= da_len) {
clearInterval(task_id);
task_id = null;
}
working = false;
}
}, 1);
}