Progress Bar with Nested For-loops

2019-09-14 20:55发布

Looping over two different arrays, both for-loops nested within each other asynchronously (as chunks and setTimeout sourced from here), and trying to use the progress bar example from W3Schools here (the Label one).

The sourced (slightly modified for a 'done' callback) asynchronous function:

function loopAsync(array, fn, done, chunk, context) {
    context = context || window;
    chunk = chunk || 10;
    var index = 0;

    function doChunk() {
        var cnt = chunk;
        while (cnt-- && index < array.length) {
            // callback called with args (value, index, array)
            fn.call(context, array[index], index, array);
            ++index;
            //console.log("index is " + index);
            progressBar(index);
        }
        if (index < array.length) {
            // set Timeout for async iteration
            setTimeout(doChunk, 1);
        } else {
            done && done();
        }
    }
    doChunk();
}

Regardless of being asnychronous, these are the same problems even with a normal for-loop:

  1. The W3School example is using setInterval, which is inaccurate since the for-loops may already finish processing before setInterval is.

  2. There are two nested for-loops, so instead of tracking the progress of (for example) i in for (var i=0...), it needs to track the first loop * the second loop for accuracy (as to not appear stopped - especially because the second loop will likely have a larger array length than the first).

For example:

Asynchronously using the linked example above:

loopAsync(arr1, function (item1) {
    loopAsync(arr2, function (item2) {
        //Comparing or processing item1 with item2
    });
}, doNext);

Or, basically the same without asynchronous looping:

for (var item1 = 0; item1 < arr1.length; ++item1) {
    for (var item2 = 0; item2 < arr2.length; ++item2) {
        //Doing things... need to track progress of both?
    }
}
  1. Needs to be generic, able to be used in any nested (or non-nested) for-loop operation.

How should these problems be addressed, preferably without jquery?

1条回答
Root(大扎)
2楼-- · 2019-09-14 21:28

i think thats just need basic increment. you can use something like this:

function progress(total) {
  this.inc = (total !== 0? this.inc || 0: -1) + 1;
  var percentage = Math.floor(this.inc / total * 100);
  document.write('Processing ' + this.inc + '/' + total + ' ' + percentage + '%<br/>');
}

var arr1 = [1,2,3,4,5];
var arr2 = [1,2,3,4,5,6,7,8,9];

for (var item1 = 0; item1 < arr1.length; ++item1) {
  for (var item2 = 0; item2 < arr2.length; ++item2) {
      progress(arr1.length * arr2.length);
  }
}

// reseting counter
progress(0);

// count another progress
var arr3 = [1,2,3];

for (var item1 = 0; item1 < arr1.length; ++item1) {
  for (var item2 = 0; item2 < arr2.length; ++item2) {
    for (var item3 = 0; item3 < arr3.length; ++item3) {
        progress(arr1.length * arr2.length * arr3.length);
    }
  }
}


another example with random execution time (use promise to doing async process)

function progress(total) {
  this.inc = (total !== 0? this.inc || 0: -1) + 1;
  document.getElementById('progress').innerHTML = 'Processing ' + Math.floor(this.inc / total * 100) + '%';
}

function processing_something(callback) {
  setTimeout(function(){
    callback();
    //execution between 1 to 10 secs
  }, Math.floor(Math.random() * 10) * 1000);
}

var arr1 = [1,2,3,4,5];
var arr2 = [1,2,3,4,5,6,7,8,9];

for (var item1 = 0; item1 < arr1.length; ++item1) {
  for (var item2 = 0; item2 < arr2.length; ++item2) {
      new Promise(function(resolve) {
      	//do something that require time
        processing_something(resolve);
      }).then(function(){
      	 progress(arr1.length * arr2.length);
      });
  }
}
<div id="progress"></div>

查看更多
登录 后发表回答