嵌套.then()函数

时间:2019-07-17 10:22:56

标签: javascript ecmascript-6 es6-promise

嵌套多个then函数是错误的做法吗?说“执行此功能,完成后执行此功能”(依此类推)似乎很合逻辑,但是代码看起来很糟糕。

如果有帮助,我最初在firestore的上下文中进行了此查询,先获取用户详细信息,然后获取文档

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

有其他选择吗?想到的就是这样

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

但是即使那样,经过几次.then()之后,它看起来还是可能变得复杂

3 个答案:

答案 0 :(得分:2)

从第一个外部.then返回Promise,然后在第二个外部.then中使用resolve值,而没有任何嵌套的.then

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

请确保不要过早catch-如果链中任何地方出现错误,通常您会希望停止正常执行并直接结束操作(例如,告诉用户有错误) )。

如果您担心代码的可读性,请考虑使用async / await(并为较早的浏览器转换生产代码):

// 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
}

答案 1 :(得分:2)

这取决于您要执行的操作:如果需要访问传递到then 的结果,并且需要访问{{ 1}},嵌套是合理的:

then

不过,通常,您只需要通过从doSomething() .then(result1 => { return doSomethingElse() .then(result2 => { return result1 + result2; }); }) .then(combinedResult => { // Use `combinedResult`... }) .catch(/*...*/); 处理程序返回后续操作中的promise,就可以在链中传递单个值:

then

这样做可以将创建的承诺doSomething() .then(result => { return doSomethingElse(result); }) .then(lastResult => { // `lastResult` is the fulfillment value from `doSomethingElse(result)` }) .catch(/*...*/); 解析为查询中then返回的承诺。 (“ 解决承诺 某事”表示您已根据解决的事情做出了承诺的和解。如果您将其解决为另一个承诺,其解决取决于其他承诺的解决。)

看看您的Firebase示例,我可能无需嵌套即可:

get()

答案 2 :(得分:1)

您应该链接promise,并且还可以命名函数,恕我直言,IMHO可以显着提高可读性。考虑这样的事情

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