简体   繁体   中英

node.js: apply a list of async functions to each item of a list of lists

I have a list of persons, each one contains a list of image urls.
I need to download each url, then calculate a 'signature' for that image, verify that it is unique, and then save it to file system.
My current approach is: two nested async.each calls, and one async.waterfall to check and save image (omitting error handling for simplicity): var async = require('async'); var request = require('request');

var syncPersonsImages = function(persons, images, callback) {
  async.each(
    persons,
    function(person, callbackPerson) {
      async.each(
        person.imageUrls,
        function(imageUrl, callbackImage) {
          download(imageUrl, function(err, image) {
            downloadPost(callbackImage);
          });
        },
        function(err) {
          callbackPerson();
        }
      );
    },
    function(err) {
      callback(null, persons);
    }
  );

  function download() {
    request(
      { uri: image.url },
      function(err) {
        callback(err, image);
      },
      function(contents, res) {
        image.contents = res.contents;
        callback(null, image);
      }
    );
  }

  function downloadPost(image, callback) {
    async.waterfall(
      [
        getSignatureFromImage,
        findSimilarSignatureImage,
        saveImage,
      ],
      function (err, image) {
        callback(image);
      }
    );
  }

  function getSignatureFromImage(image, callback) {
    image.signature = crypto.createHash('md5').update(image.url).digest('hex');
    callback(null, image);
  }

  function findSimilarSignatureImage(image, callback) {
    if (existsAlready(image.signature)) { // this function is not shown but it's behaviour is clear...
      image.isNew = true;
    }
    callback(null);
  }

  function save(image, callback) {
    if (image.isNew) {
      img.save(function(err) {
        console.log('image', image.url, 'saved');
        callback(null, image);
      }
    } else {
      callback(null, null);
    }   
  }

};

The problem is that the syncPersonsImages method never terminates...
Any suggestion?
Is my approach at least teoretically correct?

Overall I think the approach is sound. A couple of points. I think you have unnecessarily wrapped some of your callbacks. For example, this:

  function(person, callbackPerson) {
    async.each(
      person.imageUrls,
      function(imageUrl, callbackImage) {
        download(imageUrl, function(err, image) {
          downloadPost(callbackImage);
        });
      },
      function(err) {
        callbackPerson();
      }
    );
  },
  function(err) {
    callback(null, persons);
  }
);

could be changed to:

function(person, callbackPerson) {
  async.each(
    person.imageUrls,
    function(imageUrl, callbackImage) {
      download(imageUrl, function(err, image) {
        downloadPost(callbackImage);
      });
    }, callbackPerson);
}, callback);

... depending on whether or not you want your async.each calls to bail the first time there is an error.

Also,you defined your download method without parameters.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM