Passport.js中done函数的返回值是什么?其设计原因是什么?
return done(...)的设计逻辑 Let me break this down clearly for you—since I’ve spent a lot of time working with Passport.js, this is a question I’ve seen come up often.
1. done函数本身的返回值
First off: the done callback provided by Passport returns undefined. Its entire purpose isn’t to send a value back to your code—it’s a way to communicate the result of your authentication logic to Passport itself.
When you call done(error, user, info), you’re telling Passport three possible outcomes:
- If you pass an
error(first argument notnull), Passport treats this as a server error and triggers its error-handling flow. - If you pass
nullas the first argument and auserobject, Passport proceeds to serialize the user and complete the authentication. - If you pass
nullandfalse(plus optionalinfo), Passport treats this as an authentication failure (e.g., wrong password) and moves to the failure flow.
The done function doesn’t produce any meaningful return value for your code to use—it’s all about signaling to Passport what to do next.
2. return done(...)的返回值
When you write return done(...), you’re just returning the result of done()—which, as we said, is undefined. The return here isn’t about the value being returned; it’s about stopping execution of the current function.
For example, in a typical verify callback:
passport.use(new LocalStrategy((username, password, done) => { User.findOne({ username: username }, (err, user) => { if (err) return done(err); // Stop here if there's a DB error if (!user) return done(null, false, { message: 'Incorrect username.' }); if (!user.validPassword(password)) return done(null, false, { message: 'Incorrect password.' }); return done(null, user); // Only reach this if all checks pass }); }));
Each return done(...) ensures that once we’ve notified Passport of the result, we don’t run any extra code in the callback (like accidentally checking the password again or sending duplicate responses).
3. 为什么要采用这样的设计?
This design boils down to three key goals for Passport’s architecture:
- Asynchronous flow control: Most authentication logic involves async operations (database queries, API calls, etc.). Using a callback like
donelets you signal completion of these async tasks to Passport, which can’t rely on synchronous return values. - Clear separation of concerns: By using
doneto pass authentication results, Passport handles the standardized flow (error handling, serialization, failure redirects) while your code focuses on the business logic of verifying credentials. You don’t have to worry about returning the right value—just calldonewith the right arguments, and Passport takes care of the rest. - Defensive coding: The
return done(...)pattern is a convention that helps developers avoid bugs from unintended code execution after the authentication result is sent. It’s not required by Passport, but it’s a best practice to keep your logic clean and predictable.
内容的提问来源于stack exchange,提问作者Michael Kurowski

