3 ms·
While async and await is a welcome change, callback hell is mostly a symptom of the programmer's own doing. It is possible to have callback hell in any async p
by educar 10y ago
While async and await is a welcome change, callback hell is mostly a symptom of the programmer's own doing. It is possible to have callback hell in any async programming stack/framework.
In C++, you usually don't write anonymous functions and lambdas at will. You make proper named functions out of them and write unit tests even. Same applies to js. It's really just a matter of discipline and having a culture of writing manageable code.
If someone is curious how this can be done, please post a link here and I can help clean it up.
- krisdol 10y agoFor a good starting point for anyone who doesn't know how to handle callback hell without promises or transpiled features, this is a must read: http://callbackhell.com/ http://callbackhell.com/.
- Const-me 10y agoIf you're the author of that site, please fix HTML and/or CSS for code snippets: both IE 11 and MS Edge 25 show your code on a single line.
- Kequc 10y agoI'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/bcd80980184ed480b864581bcdb351f4 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.
- educar 10y agoSomething 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.
- Kequc 10y agoI've amended `try1.js` and `try2.js` to my gist. https://gist.github.com/Kequc/bcd80980184ed480b864581bcdb351f4 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.