如何在array.map()循环中每50次迭代设置一次超时?

时间:2015-11-04 23:37:42

标签: javascript node.js

问题:如何每50次迭代使files.map(...)暂停一次?

问题: gm().size()是一项非常昂贵的功能。在大约300次迭代后完全摔到床上。我有一个理论认为,如果我让这个功能保持不变,这将得到纠正。

     //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.
            }

          });
      });

3 个答案:

答案 0 :(得分:1)

您可以使用async.mapSeries。等待每次迭代完成后再继续下一次。

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);

答案 1 :(得分:1)

或者,实施您自己的批处理器。 map的替代方法一次只处理options.batchSize个项目,然后休息options.timeoutMs以便给应用程序时间做其他事情。

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);
}

答案 2 :(得分:1)

抱歉,我只是觉得无耻地堵塞my new library所以我会这样做。它是这样的:



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
    };
    
  });
                                     
});




修改:选中并且有效,但.data中没有entrySize,只有.width.height

编辑:已移除var i,因为我们可以使用数组索引。