简体   繁体   English

在从 firebase 收集数据之前呈现网页 - NodeJS 和 EJS

[英]Webpage is rendering before data is collected from firebase - NodeJS and EJS

I have tried using async-await, .then and now promise.我尝试过使用 async-await、.then 和现在的 promise。 I am quite new in javascript development.我是 javascript 开发的新手。

The code编码

indexRouter.get('/dashboard', checkSignIn, async(request, response) => {
    snapshot = await db.doc('users/accounts').get()
    sites = snapshot.data()['sites']
    const userId = request.session.userId
    snapshot = await db.doc(`users/${userId}`).get()
    var linkedSites = snapshot.data()['linked sites']
    let getDs = new Promise((resolve,reject)=>{
        console.log("1")
            linkedSites.forEach((site) =>{
                console.log("2")
            db.doc(`users/${userId}`).collection(site).get()
            .then((snapshot)=>{
                console.log("3")
                snapshot.forEach((doc) => {
                console.log("4")
                console.log(doc.id)
                emailId = doc.id
                keys = doc.data()['keys']
                var passwordEncrypt = doc.data()['password']
                password = cryptoJS.....
                details.push({site:{'email': emailId, 'password': password, 'keys': keys}})
                })
            })
        })
        console.log("5")
        console.log(details)
        resolve(details)
        }

    );

    getDs.then((details)=>{
        console.log("rendering")
        response.render('dashboard', {'details':details, 'linkedSites': linkedSites, 'sites': sites})
    })
}

I am getting the response我收到了回复

1
2
2
5
[]
rendering
error: ...details not found in ejs
3
4
rsp121@gmail.com
3
4
test@gmail.com

According to the output, it seems like db.doc line after console.log(2) is getting executed after a certain time and resolve(details) is sent before.根据 output,console.log(2) 之后的 db.doc 行似乎在一段时间后被执行,并且之前发送了 resolve(details)。


Found a solution to the problem:找到了解决问题的方法:

indexRouter.get('/dashboard', checkSignIn, async(request, response) => {
    snapshot = await db.doc('users/accounts').get()
    sites = snapshot.data()['sites']
    const userId = request.session.userId
    snapshot = await db.doc(`users/${userId}`).get()
    var linkedSites = snapshot.data()['linked sites']
    if(linkedSites){
        const getSnapshot = (site) => {
            return new Promise(resolve => {
                db.doc(`users/${userId}`).collection(site).get()
                .then((snapshot) =>{
                    snapshot.forEach((doc) =>{
                        emailId = doc.id
                        keys = doc.data()['keys']
                        var passwordEncrypt = doc.data()['password']
                        password = cryptoJS
                        details[site] = {'email': emailId, 'password': password, 'keys': keys}
                        resolve(true)
                    })
                })
            })
        }

        Promise.all(linkedSites.map(getSnapshot)).then(()=>{
            console.log(linkedSites)
            response.set('Cache-Control', 'no-store, no-cache, must-revalidate, private')
            response.render('dashboard', {'details':details, 'linkedSites': linkedSites, 'sites': sites})
        })
    }

The problem is your promise resolved before the db.doc is resolved, and as your db.doc promise is inside a loop.问题是您的 promise 在db.doc解决之前已解决,并且您的 db.doc promise 在循环内。 So, you should be using the promise.all The below code should work for you.所以,你应该使用promise.all下面的代码应该适合你。

indexRouter.get("/dashboard", checkSignIn, async (request, response) => {
  snapshot = await db.doc("users/accounts").get();
  sites = snapshot.data()["sites"];
  const userId = request.session.userId;
  snapshot = await db.doc(`users/${userId}`).get();
  var linkedSites = snapshot.data()["linked sites"];
  let getDs = new Promise((resolve, reject) => {
    const promises = [];
    console.log("1");
    linkedSites.forEach((site) => {
      console.log("2");
      promises.push(
        new Promise((internalResolve) => {
          db.doc(`users/${userId}`)
            .collection(site)
            .get()
            .then((snapshot) => {
              console.log("3");
              snapshot.forEach((doc) => {
                console.log("4");
                console.log(doc.id);
                emailId = doc.id;
                keys = doc.data()["keys"];
                var passwordEncrypt = doc.data()["password"];
                password = cryptoJS;
                details.push({
                  site: {
                    email: emailId,
                    password: password,
                    keys: keys,
                  },
                });
                internalResolve();
              });
            });
        })
      );
    });
    Promise.all(promises).then(() => {
      console.log("5");
      console.log(details);
      resolve(details);
    });
  });
  getDs.then((details) => {
    console.log("rendering");
    return response.render("dashboard", {
      details: details,
      linkedSites: linkedSites,
      sites: sites,
    });
  });
});

More cleaner with async/await .使用async/await更干净。

indexRouter.get("/dashboard", checkSignIn, async (request, response) => {
  snapshot = await db.doc("users/accounts").get();
  sites = snapshot.data()["sites"];
  const userId = request.session.userId;
  snapshot = await db.doc(`users/${userId}`).get();
  var linkedSites = snapshot.data()["linked sites"];
  console.log("1");
  linkedSites.forEach(async (site) => {
    console.log("2");
    const snapshot = await db.doc(`users/${userId}`).collection(site).get();
    console.log("3");
    snapshot.forEach((doc) => {
      console.log("4");
      console.log(doc.id);
      emailId = doc.id;
      keys = doc.data()["keys"];
      var passwordEncrypt = doc.data()["password"];
      password = cryptoJS;
      details.push({
        site: {
          email: emailId,
          password: password,
          keys: keys,
        },
      });
    });
  });
  console.log("rendering");
  return response.render("dashboard", {
    details: details,
    linkedSites: linkedSites,
    sites: sites,
  });
});

This is your code corrected, optimized and using last especifications of ECMA Script, the error is as the other comment said you are no waiting for the result of promises inside your "new Promise.." declaration.这是您的代码更正、优化并使用 ECMA 脚本的最后一个 especifications,错误是正如其他评论所说,您无需等待“新 Promise..”声明中的承诺结果。 Dont foget to use try/catch inside async functions if you have not a top error handler.如果您没有顶级错误处理程序,请不要在异步函数中使用 try/catch。

The optimization is in firsts snapshot variables, this way you are getting data in parallel instead secuantially.优化首先是快照变量,这样您就可以并行获取数据,而不是安全地获取数据。

indexRouter.get('/dashboard', checkSignIn, async (request, response) => {
try {
    let details = [];
    const userId = request.session.userId
    let [snapshot1, snapshot2] = await Promise.all([db.doc('users/accounts').get(), await db.doc(`users/${userId}`).get()])
    let sites = snapshot1.data()['sites']
    var linkedSites = snapshot2.data()['linked sites'];

    await Promise.all(
        linkedSites.map((site) =>
            db.doc(`users/${userId}`).collection(site).get()
                .then((snapshot) => {
                    snapshot.forEach((doc) => {
                        emailId = doc.id
                        keys = doc.data()['keys']
                        var passwordEncrypt = doc.data()['password']
                        password = cryptoJS
                        details.push({ site: { 'email': emailId, 'password': password, 'keys': keys } })
                    })
                })
        )
    )

    response.render('dashboard', { 'details': details, 'linkedSites': linkedSites, 'sites': sites })
} catch (e) {
    //Render error you want
}})

linkedSites.map.... return an array of Promises that in the end are wrapped inside Promise.all and Promise.all wait until all promises are fullfilled or one of them is rejected in this last case your code goes to catch without reach the line response.render inside the try. linkedSites.map.... 返回一个 Promise 数组,这些 Promise 最终被包装在 Promise.all 和 Promise.all 中,直到所有的承诺都被满足,或者没有它们的情况下最后一个被拒绝行 response.render 在 try 中。 You can avoid this catching locally the error of each promise in the map using您可以避免在本地捕获 map 中每个 promise 的错误

 .then((snapshot) => {
 ...
}).catch(e=> { /*Do something with the rror*/})

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM