#javascript #node.js #firebase #promise #google-cloud-functions
# #javascript #node.js #firebase #обещание #google-cloud-функции
Вопрос:
Я новичок в Node.js и я борюсь с обещаниями даже после прочтения руководств, предоставленных другими пользователями stackflow. Я уже потратил на это целый вечер, и я ищу помощи. Я получаю следующую ошибку «Функция вернула неопределенное, ожидаемое обещание или значение». Мой код приведен ниже. Что я делаю не так? У меня также есть подозрение, что я должен использовать await / async, потому что похоже, что мой код выполняется, не дожидаясь завершения первого get.
const admin = require('firebase-admin');
const functions = require('firebase-functions');
var db = admin.firestore();
exports.declinedRequest = functions.firestore
.document('requests/{requestId}')
.onUpdate((change, context) => {
const newValue = change.after.data();
const status = newValue.status;
const request = context.params.requestId;
var registrationToken;
var message;
if(status=="created") {
console.log('Checkpoint1 ',context.params.requestId);
newValue.friends.forEach(doc => {
console.log('Checkpoint 2: ', doc);
var usersRef = db.collection('users');
var query = usersRef.where('mobile', '==', doc).get()
.then(snapshotFriend => {
if (snapshotFriend.empty) {
console.log('Checkpoint3.');
return;
}
snapshotFriend.forEach(mobile => {
registrationToken = mobile.data().fcmToken;
console.log('FCM token =>', registrationToken);
if (!registrationToken) {
console.log('No fcmToken available');
return;
}
message = {
notification: {
body: "Request still available from " newValue.requesterName,
sound: "default",
badge: 1
},
data: {
requestId: `${request}`
}
};
console.log('FCM token message created');
})
})
})
} else {
return;
}
return admin.messaging().sendToDevice(registrationToken, message)
.then(function (response) {
console.log("Successfully sent message:", response)
})
.catch(function (error) {
console.log("Error sending message:", error);
})
})
Комментарии:
1. Основная проблема заключается в том, что вы не возвращаете обещание с верхнего уровня вашей функции, когда оно входит в первый
if
блок. Возвращает вложенные в обратные вызовы и функции не возвращаются с верхнего уровня. Кроме того, у вас никогда не будет никаких обязательств использовать async / await, поскольку это просто удобный синтаксис для того же, что вы делаете с использованием promisesthen
.2. Вам может помочь просмотр этой серии видеороликов об облачных функциях и о том, как использовать обещания в нем. Это также помогает начать с простой функции, а затем добавить сложность позже. Прямо сейчас то, что у вас есть, довольно сложно для тех, кто новичок в node.
3. Спасибо тебе, Дуг. Я смотрел этот видеоряд, но не встречал никаких предложений о том, как это исправить, когда if находится на верхнем уровне. Я внес одно изменение на основе ваших отзывов (обновленный код выше). Однако теперь похоже, что возврат внизу выполняется раньше, чем приведенный выше код. Я изо всех сил пытаюсь вставить ожидание перед возвращением. Есть какие-нибудь предложения?
Ответ №1:
Попробуйте приведенный ниже код, надеюсь, это сработает.
const admin = require('firebase-admin');
const functions = require('firebase-functions');
const Promise = require('bluebird');
const _ = require('lodash');
let db = admin.firestore();
exports.declinedRequest = functions.firestore
.document('requests/{requestId}')
.onUpdate((change, context) => {
const newValue = change.after.data();
const status = newValue.status;
const request = context.params.requestId;
if (status == "created") {
console.log('Checkpoint1 ', context.params.requestId);
allPromises = [];
newValue.friends.forEach(doc => {
console.log('Checkpoint 2: ', doc);
const usersRef = db.collection('users');
// query for each document return promise.
allPromises.push(queryForEachDocument(doc,request,usersRef));
});
return Promise.all(allPromises);
} else {
return Promise.reject / resolve('Whatever you want.');
}
})
function queryForEachDocument(doc,request,usersRef) {
let promiseInvoices = []
let registrationToken;
let message;
return usersRef.where('mobile', '==', doc).get().then((snapshotFriend) => {
if (_.isEmpty(snapshotFriend)) {
console.log('Checkpoint3.');
return Promise.reject(new Error('Your error'));
}
snapshotFriend.forEach(mobile => {
registrationToken = mobile.data().fcmToken;
console.log('FCM token =>', registrationToken);
if (!registrationToken) {
console.log('No fcmToken available for', newValue.requesterName);
// Do anything you want to change here.
return Promise.reject(new Error('No fcmToken available for',newValue.requesterName));
}
message = {
notification: {
body: "Request still available from " newValue.requesterName,
sound: "default",
badge: 1
},
data: {
requestId: request
}
};
console.log('FCM token message created');
// send invoice for each registrationToken
promiseInvoices.push(sendInvoice(registrationToken, message))
});
}).then(() => {
return Promise.all(promiseInvoices);
})
}
function sendInvoice(registrationToken, message) {
return admin.messaging().sendToDevice(registrationToken, message)
.then(function (response) {
console.log("Successfully sent message:", response)
})
.catch(function (error) {
console.log("Error sending message:", error);
})
}
Комментарии:
1. Спасибо, Шубхам, за исправление моего кода. Он работает хорошо, за исключением того, что я не смог заставить его развернуть с помощью Promise.reject / resolve(‘Все, что вы хотите.’). Что означает / ? Мне пришлось отказаться от отклонения и / или заставить его работать. Вы знаете почему?
2. Вы можете либо повторно отправить эту вещь, либо отклонить не оба, а то, что вы хотите сделать.
return Promise.reject / resolve('Whatever you want.')
Итак, в случае успеха вы можете повторно отправить вещь, и если вы считаете, что должна быть ошибка, которую вы можете вызвать reject, я не могу найти, что именно вы хотите сделать, поэтому я написал , вы можете написать return Promise.resolve(‘Все, что вы хотите.’) или returnPromise.reject (‘Все, что вы хотите.’);