Как избежать jimp, блокирующего код node.js

Я использую Jimp для управления некоторыми фотографиями.

У меня есть массив с фотографиями. Вот так:

var images = ['.../pic-1.jpg', '.../pic-2.jpg', '.../pic-3.jpg', '.../pic-4.jpg'];

И это код для их управления:

images.forEach(function(image){
  jimp.read(image, function(err, img){
    img.quality(90, function(){
      console.log("done with this image!");
    });
  });
});

Это хорошо работает, когда записывается каждое изображение. Однако он блокирует код, и если я попробую это:

var processed = 0;

images.forEach(function(image){
  jimp.read(image, function(err, img){
    img.quality(90, function(){
      processed++;
      document.querySelector('p').textContent = 'processed images: ' + processed;
    });
  });
});

он не обновляет текст до тех пор, пока все изображения не будут обработаны. Как я могу это сделать, чтобы обновлять текст каждый раз, когда изображение обрабатывается?

Ответ 1

Может показаться, что это происходит потому, что все происходит параллельно, а не последовательно, или, возможно, самое время тратится на img.quality() и это задача с интенсивным процессором, которая блокирует основной поток.

Вы можете попробовать изменить это:

images.forEach(function(image){
  jimp.read(image, function(err, img){
    img.quality(90, function(){
      processed++;
      document.querySelector('p').textContent = 'processed images: ' + processed;
    });
  });
});

примерно так:

let processed = 0;
let f = () => {
  jimp.read(images[processed], function(err, img){
    img.quality(90, function(){
      processed++;
      document.querySelector('p').textContent = 'processed images: ' + processed;
      if (processed < images.length) setImmediate(f);
    });
  });
};

Вы также можете изменить setImmediate на setTimout с некоторым значением таймаута, которое позволит потоку пользовательского интерфейса рисовать на экране то, что ему нужно сделать. Вы даже можете использовать window.requestAnimationFrame() для этого.