部署Firebase Functions时遇Promise相关报错与警告求助
Hey there! Let's work through those two promise errors you're hitting when deploying your Node.js Firebase Functions. These are ESLint rules designed to keep your promise code clean and bug-free, so let's break down what each one means and how to fix them.
What Do the Errors Mean?
1. Avoid nesting promises promise/no-nesting (Warning)
This rule is all about avoiding "promise hell"—when you nest then() calls inside other then() calls. Nesting makes your code harder to read, debug, and maintain, like a tangled mess of callbacks.
2. Each then() should return a value or throw promise/always-return (Error)
ESLint wants every then() callback to either return a value (could be another promise or a plain value) or throw an error. This ensures the promise chain behaves predictably—without it, you might end up with unhandled promises or functions that finish early before your code runs.
Let's Fix Your Code
First, let's assume your original code looks something like this (a common notification function setup matching your snippet):
"use-strict"; const functions = require("firebase-functions"); const admin = require("firebase-admin"); admin.initializeApp(functions.config().firebase); exports.sendNotification = functions.firestore.document('notifications/{docId}').onCreate((snap) => { const notificationData = snap.data(); // Problem: Nested promises + missing returns admin.firestore().collection('users').doc(notificationData.userId).get() .then(userDoc => { const token = userDoc.data().fcmToken; const payload = { notification: { title: notificationData.title, body: notificationData.body } }; // Nested then() violates no-nesting rule admin.messaging().sendToDevice(token, payload) .then(response => { console.log('Notification sent!', response); // No return here violates always-return }) .catch(err => console.error(err)); // No return from this then() either }) .catch(err => console.error(err)); // No return from the main function });
Fixed Version (Chained Promises)
Here's how to rewrite it to satisfy both rules:
"use-strict"; const functions = require("firebase-functions"); const admin = require("firebase-admin"); admin.initializeApp(functions.config().firebase); exports.sendNotification = functions.firestore.document('notifications/{docId}').onCreate((snap) => { const notificationData = snap.data(); // 1. Return the entire promise chain so Firebase tracks execution return admin.firestore().collection('users').doc(notificationData.userId).get() .then(userDoc => { if (!userDoc.exists) throw new Error("User not found"); const token = userDoc.data().fcmToken; if (!token) throw new Error("User has no FCM token"); const payload = { notification: { title: notificationData.title, body: notificationData.body } }; // 2. Return the next promise to chain instead of nesting return admin.messaging().sendToDevice(token, payload); }) .then(response => { console.log('Notification sent successfully:', response); // 3. Return a value to satisfy always-return return null; }) .catch(err => { console.error('Error processing notification:', err); // 4. Re-throw the error so Firebase knows the function failed throw err; }); });
Even Better: Use Async/Await
If you prefer cleaner, more readable code, switch to async/await—it eliminates promise nesting entirely and makes the logic look like synchronous code:
"use-strict"; const functions = require("firebase-functions"); const admin = require("firebase-admin"); admin.initializeApp(functions.config().firebase); // Mark the function as async exports.sendNotification = functions.firestore.document('notifications/{docId}').onCreate(async (snap) => { try { const notificationData = snap.data(); const userDoc = await admin.firestore().collection('users').doc(notificationData.userId).get(); if (!userDoc.exists) throw new Error("User not found"); const token = userDoc.data().fcmToken; if (!token) throw new Error("User has no FCM token"); const payload = { notification: { title: notificationData.title, body: notificationData.body } }; const response = await admin.messaging().sendToDevice(token, payload); console.log('Notification sent successfully:', response); return null; } catch (err) { console.error('Error processing notification:', err); throw err; } });
Key Takeaways
- Return the promise chain: Firebase Functions needs to know when your code finishes running—returning the top-level promise ensures it doesn't terminate early.
- Avoid nesting: Chain promises instead of nesting them, or use async/await for even cleaner code.
- Return or throw in every then(): Every
then()callback should either return a value/promise or throw an error to keep the chain predictable.
内容的提问来源于stack exchange,提问作者sonu sharma

