Hacker News new | past | comments | ask | show | jobs | submit login

I've got a classic callback hell type situation that just cropped up in one of my applications. We are using an image library to change an uploaded file into a background image for the header.

https://gist.github.com/Kequc/bcd80980184ed480b864581bcdb351...

I've toyed with separating each stage into sections, but I still need a callback to return at the end of it. Which seems to necessitate an anonymous function every step of the way.

What is your proposal.




Something like this.

  function resizeImage(req, res, next) {
      lwip.open(req.file.buffer, 'jpg', function (err, img) {
          if (err) return callback(err);

          var image = new Image(img);
          let ratio = (image.width() > 960 ? (960 / image.width()) : 1);

          async.series([
              image.scale.bind(image, ratio),
              image.crop.bind(image, image.width(), Math.min((image.width() / 2), image.height())),
              image.write.bind(image, req.params['id'], "TITLE_IMAGE", buffer, "image/jpeg")
          ], next);
      });
  }

  router.post('/:id/title-image', function (req, res, next) {
      resizeImage(req, res, function (err) {
          if (err) res.sendStatus(400);

          res.sendStatus(200);
      });
  });



This is just my "way" of writing things:

1. I write with 4 spaces because it lets me know when I should refactor my code into something more readable.

2. I usually move route handlers to it's own file. So it will read like ``` router.post('/:id/title-image', routes.resizeImage); ``` The idea is that routes code simply goes through the model code and send the right http status codes.

3. async is your friend :-) In general, I try to model my model APIs with async in mind.

I can give it a better shot later today if you had any comments on my first try.


I've amended `try1.js` and `try2.js` to my gist.

https://gist.github.com/Kequc/bcd80980184ed480b864581bcdb351...

I'm not sure async is my new favourite library. It seems to obfuscate a lot of behaviour out of my hands, then it returns the result of each function as an array. During processing it doesn't remain clear to me what the value of `image` is. It appears like the crop operation is being applied to the original image rather than the scaled one.

That said - it does seem to work?

Another alternative, since I am calculating the dimensions of the image to start out. Something that is easier to perceive once the code is a bit more organised like this. Is to use the library's built in `batch` functionality.

It wasn't possible because I didn't have the image dimensions up front. But now I do. So I used that approach instead of async in `try2.js`. This refactor doesn't help in situations where the result of the previous callback is important.

Would a Promise be the best fix then? Promises seem to do the same thing as async but in a more javascripty way... hey, you said no need.




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: