Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How To Solve NodeJS Method Priority Problem

In this case, method 3 works first and i am getting error. Its priority has to be like method 1, method 2, and method 3. Are these methods promises ? And promises work as asynchronous.

I want check if new user's username and email in use or not. If username or email are not in use, then register it.

How to i solve this problem ? I'm new at nodejs.

module.exports.addUser = function(newUser, callback) {

    // method 1
    User.countDocuments({username: newUser.username}).then(count => {
        if(count > 0) {
            console.log("username in use");
            callback("username in use", null);
            return;
        }});

    // method 2
    User.countDocuments({email: newUser.email}).then(count => {
        if(count > 0) {
            console.log("email in use");
            callback("email in use", null);
            return;
        }});

    // method 3 , this method works first
    bcrypt.genSalt(10, (err, salt) => {
        console.log("salt here");
        bcrypt.hash(newUser.password, salt, (err, hash) => {
            if(err) throw err;
            newUser.password = hash;
            newUser.save(callback);
        });
    });
};

Output:

salt here
username in use
email in use

(node:7972) UnhandledPromiseRejectionWarning: Error: Can't set headers after they are sent.
    at validateHeader (_http_outgoing.js:491:11)
    at ServerResponse.setHeader (_http_outgoing.js:498:3)
    at ServerResponse.header (C:\Users\cyclone\Desktop\my_auth\node_modules\express\lib\response.js:767:10)
    at ServerResponse.send (C:\Users\cyclone\Desktop\my_auth\node_modules\express\lib\response.js:170:12)
    at ServerResponse.json (C:\Users\cyclone\Desktop\my_auth\node_modules\express\lib\response.js:267:15)
    at User.addUser (C:\Users\cyclone\Desktop\my_auth\routes\users.js:20:17)
    at User.countDocuments.then.count (C:\Users\cyclone\Desktop\my_auth\models\user.js:48:13)
    at <anonymous>
    at process._tickCallback (internal/process/next_tick.js:189:7)
(node:7972) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:7972) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled
will terminate the Node.js process with a non-zero exit code.
events.js:183
      throw er; // Unhandled 'error' event
      ^

Error: Can't set headers after they are sent.
    at validateHeader (_http_outgoing.js:491:11)
    at ServerResponse.setHeader (_http_outgoing.js:498:3)
    at ServerResponse.header (C:\Users\cyclone\Desktop\my_auth\node_modules\express\lib\response.js:767:10)
    at ServerResponse.send (C:\Users\cyclone\Desktop\my_auth\node_modules\express\lib\response.js:170:12)
    at ServerResponse.json (C:\Users\cyclone\Desktop\my_auth\node_modules\express\lib\response.js:267:15)
    at User.addUser (C:\Users\cyclone\Desktop\my_auth\routes\users.js:22:17)
    at C:\Users\cyclone\Desktop\my_auth\node_modules\mongoose\lib\model.js:4518:16
    at model.$__save.error (C:\Users\cyclone\Desktop\my_auth\node_modules\mongoose\lib\model.js:422:7)
    at C:\Users\cyclone\Desktop\my_auth\node_modules\kareem\index.js:315:21
    at next (C:\Users\cyclone\Desktop\my_auth\node_modules\kareem\index.js:209:27)
    at C:\Users\cyclone\Desktop\my_auth\node_modules\kareem\index.js:182:9
    at process.nextTick (C:\Users\cyclone\Desktop\my_auth\node_modules\kareem\index.js:499:38)
    at _combinedTickCallback (internal/process/next_tick.js:132:7)
    at process._tickCallback (internal/process/next_tick.js:181:9)
[nodemon] app crashed - waiting for file changes before starting...
like image 521
canmustu Avatar asked Aug 29 '26 19:08

canmustu


1 Answers

The single fact that "then" is used after countDocuments does indicate that it's a promise and thus asynchronous.

The easiest solution at this point, would be to define your addUser function as async.

module.exports.addUser = async function(newUser, callback) {

  // method 1
  const count1 = await User.countDocuments({
    username: newUser.username
  });

  if (count1 > 0) {
    console.log("username in use");
    callback("username in use", null);
    return;
  };

  // method 2
  const count2 = await User.countDocuments({
    email: newUser.email
  });

  if (count2 > 0) {
    console.log("email in use");
    callback("email in use", null);
    return;
  };

  // method 3 , this method works first
  bcrypt.genSalt(10, (err, salt) => {
    console.log("salt here");
    bcrypt.hash(newUser.password, salt, (err, hash) => {
      if (err) throw err;
      newUser.password = hash;
      newUser.save(callback);
    });
  });
};

However, now it's quite pointless to have a callback function for addUser since an async function automatically returns a promise. I'd recommend doing something like so...

module.exports.addUser = async function(newUser) {

  // method 1
  const count1 = await User.countDocuments({
    username: newUser.username
  });

  if (count1 > 0) {
    throw Error("username is in use");
  };

  // method 2
  const count2 = await User.countDocuments({
    email: newUser.email
  });

  if (count2 > 0) {
    throw Error("email in use");
  };

  let result = null;
  // method 3 , this method works first
  bcrypt.genSalt(10, (err, salt) => {
    console.log("salt here");
    bcrypt.hash(newUser.password, salt, (err, hash) => {
      if (err) throw err;
      newUser.password = hash;
      result = await newUser.save(callback);
    });
  });

  return result;

};

and in use it would look like:

addUser(someUserObject).then(result=>console.log(result)).catch(error=>{
  //Example: username in use
  console.log(error.message)
});
like image 79
kemicofa ghost Avatar answered Aug 31 '26 09:08

kemicofa ghost



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!