Массив остается пустым при использовании Array.push в обещании - PullRequest
0 голосов
/ 07 марта 2019

Я пытаюсь собрать все документы из определенного файла и преобразовать их в объект вложения Sendgrid со свойством content и filename.

Шаг 1 и 2 работают. После шага 2 у меня есть массив объектов с некоторыми данными документа, такими как имя файла, тип, URL хранилища и т. Д.

На шаге 3 я хочу получить фактический файл на основе URL-адреса хранилища и создать объект вложения Sendgrid. В качестве свойств требуется content и filename.

Однако, с моим текущим кодом, массив вложений остается пустым, когда я регистрирую переменную.

Мой код:

export const onStatusChanged = functions.database.ref(`files/{fileID}/general/status`).onUpdate(async (change, context) => {
    const prevStatus = change.before.val();
    const currentStatus = change.after.val();

    if (prevStatus === currentStatus) return null;

    if (currentStatus === 'email') {
        // 1. Get file data
        const snapshot = await change.after.ref.parent.parent.once('value');
        const file = snapshot.val();

        // 2. Get documents
        const documents = getDocuments(file.documents);
        console.log(documents);

        // 3. Create attachments
        const attachments = [];

        documents.forEach(document => {
            axios.get(document.url, { responseType: 'arraybuffer' }).then(image => {
                attachments.push({ content: Buffer.from(image.data).toString('base64'), filename: document.name });
            }).catch(error => {
                console.log(error)
            })
        });

        console.log(attachments) // []

        // 4. Create email object

        // 5. Send email
    }

    return null;
})

Я думал, используя обещание, мой код синхронен?

РЕДАКТИРОВАТЬ: сначала у меня был этот код

    // 3. Create attachments
    const attachments = documents.map(document => {
        const image = await axios.get(document.url, { responseType: 'arraybuffer' });
        return attachments.push({ content: Buffer.from(image.data).toString('base64'), filename: document.name });
    })

    console.log(attachments) // [ Promise { <pending> } ]

Ответы [ 2 ]

1 голос
/ 07 марта 2019

Я думаю, что вы неправильно понимаете использование обещаний, особенно с облачными функциями. С фоновыми триггерами Cloud Functions вы обязаны вернуть обещание, которое разрешается, когда вся асинхронная работа полностью завершена, иначе работа будет закрыта. Прямо сейчас вы возвращаете ноль, что не правильно.

Кроме того, attachements, похоже, не накапливает обещания. Он накапливает другие объекты, которые бесполезны для асинхронного программирования.

Подробнее в документации: https://firebase.google.com/docs/functions/terminate-functions

0 голосов
/ 07 марта 2019

Изменил код обратно на async / await и добавил Promise.all().Он работает так, как я хочу сейчас.

Код:

    const attachments = await Promise.all(documents.map(async document => {
        const image = await axios.get(document.url, { responseType: 'arraybuffer' });
        return { content: Buffer.from(image.data).toString('base64'), filename: document.name };
    }));
...