Sto attraversando un momento molto difficile scrivere un codice pulito con un semplice login / login manager utente. Sto cercando di evitare l'inferno di callback / callback e non vedo alcun vantaggio nell'usare il presunto async / wait più pulito.
Prendi ad esempio il mio codice di registrazione utente. Deve eseguire 3 promesse in sequenza
-
Assicurati che l'utente sia unico nel database
-
Hash la password
-
Inserisci l'utente nel database
Voglio
-
Registra eventuali errori in ogni singola chiamata promessa (es. errore db)
-
registra il risultato finale nella funzione di livello più alto (ad esempio, registra con successo)
-
Restituisce una risposta HTTP dal chiamante.
Sembra proprio ora
hashPassword(password){
let self = this;
return bcrypt.hash(password, 10)
.then(function(hash) {
return hash;
})
.catch(function(err){
self.logger.error('failed to hash password');
self.logger.error(err);
return Promise.reject(err)
});
}
insertUser(email, passwordHash){
let self = this;
let data = {
email: email,
password: passwordHash
};
return this.collection.insertOne(data)
.then(function(res) {
self.logger.info('inserted ${email} into db');
return res;
})
.catch(function(err){
self.logger.error('failed to add user to db');
self.logger.error(err);
return Promise.reject(err)
});
}
findUser(email){
let self = this;
return this.collection.findOne({email:email})
.then(function(element) {
if(!element){
self.logger.info('user ${email} not found');
}
return element;
})
.catch(function(err){
self.logger.error('failed to query user ${email}');
self.logger.error(err);
return Promise.reject(err);
});
}
registerUser(email, password){
let self = this;
return this.findUser(email)
.then(function(element){
if(element){
self.logger.error('user ${email} already exists');
// now what do i do here for the caller?
// reject the promise? resolve with an err code?
return Promise.reject()
}
// what if this one fails? how will the caller know..
return self.hashPassword(password);
})
.then(function(hash){
return self.insertUser(email, hash);
})
.then(function(){
self.logger.info('registered user ${email}');
})
.catch(function(err){
self.logger.error('failed to register user');
return Promise.reject(err)
});
}
In realtà sono super constrongvole con le funzioni di base ( findUser
, hashPassword
, insertUser
). Ma il registerUser
ha senso. Il fatto che tu riceva promesse entro una chiamata di then
mi infastidisce davvero, per esempio, ma è proprio così che va. Il vero problema qui è che, se una delle tre chiamate nel processo fallisce, non sono sicuro di come dire al mio chiamante quale cosa è fallita.
Questo è il chiamante.
router.post('/register', function(req, res, next){
if(req.body.email && req.body.password && req.body.confirm){
userManager.registerUser(req.body.email, req.body.password)
.then(function(result){
res.sendStatus(200);
})
.catch(function(err){
res.sendStatus(400);
});
}
else {
res.sendStatus(400);
}
});
Ora ho provato a fare tutto in async / await, ma questo richiede solo un sacco di tentativi di cattura del nocciolo che, a mio parere, sono ancora peggio. Sono solo perso qui cercando di mantenere questo pulito.