【问题标题】:Nesting .then() functions嵌套 .then() 函数
【发布时间】:2019-07-17 10:22:56
【问题描述】:

嵌套多个 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() 之后,它似乎也会变得复杂

【问题讨论】:

  • 您可以在 .then 块中返回承诺,这样您只会获得一层嵌套 - javascript.info/promise-chaining
  • ...或者通过采用async/await 而不是直接处理Promise 接口来完全回避这个问题。您的代码将立即变得更具可读性。如果这(由于某种原因)不可能,这篇文章应该很有用:medium.com/@pyrolistical/…

标签: javascript ecmascript-6 es6-promise


【解决方案1】:

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

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
}

【讨论】:

  • 关于async/await 的优点(以及不必将“在 UI 中告诉用户”放在单独的 then 处理程序中)。
【解决方案2】:

这取决于你想做什么:如果你需要访问传递给then的结果你在then中执行的后续操作的结果@同时,嵌套是合理的:

doSomething()
.then(result1 => {
    return doSomethingElse()
    .then(result2 => {
        return result1 + result2;
    });
})
.then(combinedResult => {
    // Use `combinedResult`...
})
.catch(/*...*/);

不过,通常情况下,您只需要通过链传递一个值,即从 then 处理程序的后续操作中返回承诺:

doSomething()
.then(result => {
    return doSomethingElse(result);
})
.then(lastResult => {
    // `lastResult` is the fulfillment value from `doSomethingElse(result)`
})
.catch(/*...*/);

这样做会将创建的 Promise then 解析为 get() 在查询中返回的 Promise。 (“resolve a promise to something”意味着你已经做出了 Promise 的解决取决于你已经解决它的事情。如果你将它解决为另一个 Promise ,其结算取决于其他承诺的结算。)

看看您的 Firebase 示例,我可能会在不嵌套的情况下这样做:

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

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-20
      • 2020-04-02
      • 2018-04-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多