Est-ce une mauvaise pratique d'imbriquer plusieurs fonctions alors? Il semble assez logique de dire "exécutez cette fonction, et quand c'est fait, exécutez celle-ci" (et ainsi de suite) mais le code semble horrible. puis obtenir des documents
var functionOne = () =>{
console.log("I get called later");
}
var promise1 = new Promise(function(resolve, reject) {
setTimeout(function() {
resolve('foo');
}, 3000);
});
promise1.then(function(value) {
functionOne();
});
Existe-t-il des alternatives? Celui qui me vient à l'esprit est comme ça
firebaseApp.auth().signInWithEmailAndPassword(email, password).catch(function(error) {
//If error
}).then(()=>{
firebaseApp.firestore().collection(collectionName).where("associatedID", "==", authID).get().then((snapshot)=>{
snapshot.docs.forEach(doc => {
//Do stuff with data that we've just grabbed
})
}).then(()=>{
//Tell the user in the UI
});
});
Mais même dans ce cas, il semble que cela pourrait devenir complexe après quelques .then ()
3 Réponses :
Renvoyez la promesse du premier Assurez-vous de ne pas Si vous vous inquiétez de la lisibilité du code, pensez à utiliser .then externe, puis utilisez la valeur de résolution dans un deuxième .then externe, sans .then code> s: // in an async function:
try {
await firebaseApp.auth().signInWithEmailAndPassword(email, password);
const snapshot = await firebaseApp.firestore().collection(collectionName).where("associatedID", "==", authID).get()
snapshot.docs.forEach(doc => {
//Do stuff with data that we've just grabbed
});
//Tell the user in the UI
} catch(error) {
// handle errors
}
attraper trop tôt - s'il y a une erreur n'importe où dans la chaîne, vous voudrez souvent arrêter l'exécution normale et partir directement à la fin (par exemple, dites à l'utilisateur qu'il y a eu une erreur). async / await code> (et transpilez votre code de production pour les anciens navigateurs): firebaseApp.auth().signInWithEmailAndPassword(email, password)
.then(()=>{
return firebaseApp.firestore().collection(collectionName).where("associatedID", "==", authID).get()
})
.then((snapshot) => {
snapshot.docs.forEach(doc => {
//Do stuff with data that we've just grabbed
});
//Tell the user in the UI
})
.catch((error) => {
// handle errors
});
Excellent point sur async / wait (et sur le fait de ne pas avoir à mettre "Tell the user in the UI" dans un gestionnaire puis séparé).
Cela dépend de ce que vous voulez faire: si vous avez besoin d'accéder à la fois au résultat passé dans puis et au résultat d'une opération ultérieure que vous effectuez dans le puis en même temps, l'imbrication est raisonnable:
firebaseApp.auth()
.signInWithEmailAndPassword(email, password)
.then(() => firebaseApp.firestore().collection(collectionName).where("associatedID", "==", authID).get())
.then((snapshot) => {
snapshot.docs.forEach(doc => {
// Do stuff with data
});
})
.then(() => {
// Tell the user in the UI
})
.catch(function(error) {
// Handle/report error, which may be from `signInWithEmailAndPassword`, your collection query, or an error raised by your code in the `then` handlers above
});
souvent, cependant, il vous suffit de passer une seule valeur à travers la chaîne, en renvoyant la promesse de votre opération ultérieure à partir du gestionnaire puis :
doSomething()
.then(result => {
return doSomethingElse(result);
})
.then(lastResult => {
// `lastResult` is the fulfillment value from `doSomethingElse(result)`
})
.catch(/*...*/);
Cela résout la promesse puis créée à la promesse renvoyée par get () sur la requête. (" résoudre une promesse à quelque chose" signifie que vous avez fait dépendre le règlement de la promesse de ce à quoi vous l'avez résolue. Si vous le résolvez en une autre promesse , son règlement dépend du règlement de cette autre promesse.)
En regardant votre exemple Firebase, je le ferais probablement sans imbriquer:
doSomething()
.then(result1 => {
return doSomethingElse()
.then(result2 => {
return result1 + result2;
});
})
.then(combinedResult => {
// Use `combinedResult`...
})
.catch(/*...*/);
p >
Vous devez enchaîner les promesses et, également, vous pouvez nommer les fonctions, dont IMHO peut améliorer la lisibilité de manière significative. Considérez quelque chose comme ceci
const signIn = () => firebaseApp.auth().signInWithEmailAndPassword(email, password);
const onSigninError = (err) => // error handling logic here
const getCollection = () => firebaseApp.firestore().collection(collectionName).where("associatedID", "==", authID)
.get();
const processSnapshot = (snapshot) => snapshot.doc.forEach(// do stuff here
const displayMessage = () => // do stuff here
signIn()
.catch(onSigninError)
.then(getCollection)
.then(processSnapshot)
.then(displayMessage);
Vous pouvez renvoyer des promesses dans le bloc
.thenafin que vous n'obteniez qu'un seul niveau d'imbrication - javascript.info/promise-chaining... Ou évitez complètement le problème en adoptant
async / awaitau lieu de traiter directement avec l'interfacePromise. Votre code deviendra immédiatement beaucoup plus lisible. Si ce n'est pas possible (pour une raison quelconque), cet article devrait s'avérer utile: medium.com/@pyrolistical/...