Веб-страница отображается перед сбором данных из firebase - NodeJS и EJS - PullRequest
1 голос
/ 11 апреля 2020

Я пытался использовать asyn c -wait, .then и теперь обещаю. Я совершенно новичок в javascript разработке.

Код

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

Я получаю ответ

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

Согласно выводу, он выглядит как db.do c строка после console.log (2) выполняется через определенное время, и разрешение (подробности) отправляется раньше.


Найдено решение проблемы:

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

Ответы [ 2 ]

3 голосов
/ 11 апреля 2020

Проблема заключается в том, что ваше обещание разрешено до разрешения db.doc, и поскольку ваше обещание db.do c находится внутри al oop. Таким образом, вы должны использовать promise.all. Код ниже должен работать для вас.

1 голос
/ 11 апреля 2020

Это ваш код, исправленный, оптимизированный и использующий последние спецификации скрипта ECMA, ошибка в том, что, как говорится в другом комментарии, вы не ожидаете результата обещаний в вашей декларации "new Promise ..". Не забывайте использовать try / catch внутри функций asyn c, если у вас нет верхнего обработчика ошибок.

Оптимизация выполняется с помощью первых переменных снимка, таким образом вы получаете данные параллельно, а не последовательно.

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

connectedSites.map .... возвращает массив Обещаний, которые в конце обернуты в Promise.all, и Promise.all ждут, пока все обещания не будут выполнены, или одно из них будет отклонено в этом последнем случае, ваш код идет поймать без достижения линии response.render внутри try. Вы можете избежать этого, ловя локально ошибку каждого обещания на карте, используя

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