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
.then
afin que vous n'obteniez qu'un seul niveau d'imbrication - javascript.info/promise-chaining... Ou évitez complètement le problème en adoptant
async / await
au 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/...