1

I'm currently working through a tutorial to implement password reset from a node.js app, and it was required that I use the library async to clean up the code from being a callback mess. I'm relatively new to Javascript, and coming from more strongly typed languages like Java and Objective-C I'm having problems coming to grips with the liberty inherent in the language.

Anyway, I understand how each preceding function is essentially passing values down to the next function, via callbacks, but I'm having trouble understanding the point of the "err" parameter at the beginning of each callback evocation. For example, in the first function the callback evoked is done(err, token), yet the next function has token as its first parameter and not err. I'm struggling to figure out how the next function gets that token parameter and uses it when the "err" parameter is the one listed in the callback. I might be misunderstanding the concept or missing something, so any help is appreciated.

app.post('/forgot', function (req, res, next) {
    async.waterfall([function (done) {
        crypto.randomBytes(20, function (err, buf) {
            var token = buf.toString('hex');
            done(err, token);
        });
    },
        function (token, done) {
            User.findOne({ email: req.body.email }, function (err, user) {
                if (!user) {
                    return { error : 'No account with that email address exists'};
                }

                user.resetPasswordToken = token;
                user.resetPasswordExpires = Date.now() + 3600000; //1 hour

                user.save(function (err) {
                    done(err, token, user);
                });
            });
        },
        function (token, user, done) {
            var smtpTransport = nodemailer.createTransport('SMTP', {
                service: 'SendGrid',
                auth : {
                    user: "swagboi",
                    pass: "woo"
                }
            });
            var mailOptions = {
                to: user.email,
                from: '[email protected]',
                text: 'You are receiving this because you (or someone else) have requested hte reset of the password for your account. \n\n' +
                    'Pleaes click on the following link, or paste this into your browser to complete the process: \n\n' +
                    'http://' + req.headers.host + '/reset/' + token + '\n\n' +
                    'If you did not request this, please ignore this email and your password will remain unchanged. \n'
            };
            smtpTransport.sendMail(mailOptions, function (err) {
                done(err, 'done');
            });
        }
    ], function (err) {
        if (err) return next(err);
    })
});

1 Answer 1

2

If you look closely, you will see that async.waterfall accepts two arguments: A list of tasks and a callback.

done is not simply the next task in the list. It is some specific function with which async.waterfall knows how to proceed. Think about it as

function done(err, result) {
  if (err) {
    callback(err);
  } else {
    tasks[i++](result, done);
  }
}

(if done was accepting only two arguments)

I.e. only the result is passed to the next task in the list. If an error passed, the callback is called instead.

Relevant source code (which probably isn't that easy to understand).

Sign up to request clarification or add additional context in comments.

1 Comment

That clarified things perfectly, I was definitely misunderstanding the usage. Thank you so much for your help!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.