2

Question: How can I make my files.map(...) pause every 50 iterations?

Problem: the gm().size() is a very expensive function. which completely shits the bed after about 300 iterations. I have a theory that this will be remedied if I let the function keep up.

     //interaction happens that will traverse a bunch of folder and create an array of files paths
     glob(filePath + '/**/*{.png,.jpg,.gif}', function (er, files) {
        var chunksize = 50; // sets the iteration size
        if (er) return er;
          service.stuff[name] = files.map(function (entry, i) {

            return {
              identity: getIdentity()  //returns the identity(size) of images
            };

            function getIdentity() {
              if(i % chunksize == 0) { // if the 50th iteration
                (function(chunksize, i){

                  setTimeout(function () {
                  var entrySize = gm(entry)  //graphics magic will return size of images based on path.
                    .size(function (err, size) {
                      return size;
                    });
                  }, 2000); //pause for 2 seconds.

                }());

              } else {  
                var entrySize = gm(entry)
                    .size(function (err, size) {
                      return size;
                    });
              }


              return entrySize.data; //returns identity data.
            }

          });
      });
1
  • I'd strongly recommend the bluebird promise library with promisifyAll and then the form Promise.reduce(files, (function (total, file) { yourFn(file) }), 0). You can step through sequentially, image by image, instead of overloading your system. More here bluebirdjs.com/docs/features.html#promisification-on-steroids Commented Nov 5, 2015 at 0:13

3 Answers 3

1

Alternatively, implement your own batch processor. This alternative to map will only process options.batchSize items at a time, then takes an options.timeoutMs break to give the application time to do other things.

function batchMap(array, fn, options, callback) {
  var batchSize = options.batchSize || 100,
      timeoutMs = options.timeoutMs || 0;

  function map(done, todo) {
    if(todo.length > 0) {
      setTimeout(function() {
        var mapped = todo.slice(0, batchSize).map(fn);
        map(done.concat(mapped), todo.slice(batchSize));
      }, timeoutMs);
    } else {
      callback(null, done);
    }
  }

  map([], array);
}
Sign up to request clarification or add additional context in comments.

Comments

1

You can use async.mapSeries for this. It waits for each iteration to finish before continuing to the next.

npm install async

var async = require("async");
var noFile = 0;
var done = function (err, result) {
  console.log(result);
}

var yourLogic = function(file){

}
var processFile = function(file, callback) {
  if(noFile > 50) {
    setTimeout(function() {
      noFile++;
      callback(null, yourLogic(file));
    }, 1000);
  } else {
    noFile++;
    callback(null, yourLogic(file));
  }
}

async.mapSeries(files, processFile, done);

Comments

1

Sorry, I just feel like shamelessly plugging my new library so I will. It goes something like this:

var CL = require('coastline');

CL.run(function* () {
  
  var files = yield glob(filePath + '/**/*{.png,.jpg,.gif}', CL.cb());
  var chunksize = 50;
  service.stuff[name] = yield CL.map(files, function* (entry, i) {
    
    if (i && i % chunksize == 0) yield CL.sleep(2000);
    
    var entrySize = yield gm(entry).size(CL.cb());
    return {
      identity: entrySize.data
    };
    
  });
                                     
});

Edit: checked and it works, except there is no .data in entrySize, just .width and .height?

Edit: removed var i since we can use array index.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.