1
votes

Imbrication des fonctions .then ()

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 ()


2 commentaires

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'interface Promise . 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/...


3 Réponses :


2
votes

Renvoyez la promesse du premier .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
}

Assurez-vous de ne pas 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).

Si vous vous inquiétez de la lisibilité du code, pensez à utiliser 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
  });


1 commentaires

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é).



2
votes

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 >


0 commentaires

1
votes

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);


0 commentaires