Firebase云函数部署报错Each then() should return a value or throw解决方法
Hey there, that error stems from ESLint's promise/always-return rule—newer Firebase Cloud Function projects enforce this to ensure all asynchronous operations are properly chained, so the platform knows when your function has finished executing. Let's break down the issues in your code and fix them step by step:
1. Missing return in the Like branch's final then()
In your 'Like' logic, after handling the sendToDevice response, you only log a message but don't return anything. Add a simple return statement to satisfy the rule:
return admin.messaging().sendToDevice(tokens, payload).then(response => { response.results.forEach((result, index) => { console.log('FcmToken: ', tokens); const error = result.error; if (error) { console.log('Error Occured:', error); } }); console.log('User Liked'); return null; // Add this line to close the Promise chain });
2. Unreturned inner Promise in the Follow branch
In the 'Follow' section, you call followeeFollowingRef.once('value').then(...) inside the Promise.all callback, but you don't return this inner Promise. This breaks the chain, and ESLint flags it. Also, the final sendToDevice then() is missing a return:
return Promise.all([followeeUserRef.once('value')]).then(function(snaps) { var data = snaps[0].val(); const fcmToken = data.FCM_TOKEN; // Return this inner Promise to keep the chain intact return followeeFollowingRef.once('value').then(function(followeeSnapshot) { let isFollow = followeeSnapshot.exists() ? 'YES' : 'NO'; console.log(`FOLLOW ${isFollow}`); const payload = { notification: { title: '珞 You have a new follower!', body: `${followerUserName} is now following you.`, sound: 'default', icon: '', byUserId: followerUserId, byUserName: followerUserName, type: 'Follow', isFollow: isFollow, byUserPhotoUrl: followerPhotoUrl, badge : '1' } }; const tokens = fcmToken; console.log('FcmToken: ', tokens); return admin.messaging().sendToDevice(tokens, payload).then(response => { response.results.forEach((result, index) => { const error = result.error; if (error) { console.log('Error Occured:', error); } }); console.log('User Followed'); return null; // Add this return to close the chain }); }); });
3. Default return for unhandled activity types
At the end of your function, if none of the type conditions match (e.g., a new activity type is added later), you don't return anything. Add a default return to cover this edge case:
// After all if blocks return null;
Full Corrected Code
Here's the complete function with all fixes applied:
exports.sendNotificationForLikeOrFollow = functions.database.ref('/USER_MANAGEMENT/USER_ACTIVITY/{activityId}').onCreate((snap, context) => { var type = snap.val().ACTIVITY_TYPE; if (type=='Comment') { return; //There is a separate function for comment notification } if (type=='Like') { const likeUserId = snap.val().BY_USER_NODE_NAME; const publishedUserId = snap.val().PUBLISHED_USER_NODE_NAME; const puplishedContentId = snap.val().LIKE_PUBLISHED_CONTENT_NODE_NAME; const likedUserName = snap.val().BY_USER_NAME; const likedUserPhotoUrl = snap.val().BY_USER_PHOTO_URL; var publishedUserRef = db.ref("USER_MANAGEMENT/USERS/"+publishedUserId); var likedUserRef = db.ref("USER_MANAGEMENT/USERS/"+likeUserId); return Promise.all([publishedUserRef.once('value')]).then(function(snaps) { var data = snaps[0].val(); const fcmToken = data.FCM_TOKEN; const payload = { notification: { title: '❤️ You got a new like!', body: `${likedUserName} liked your artwork.`, sound: 'default', icon: '', byUserId: likeUserId, byUserName: likedUserName, type: 'Like', likedPuplishedContentId: puplishedContentId, publishedUserId: publishedUserId, byUserPhotoUrl: likedUserPhotoUrl, badge : '1' } }; const tokens = fcmToken; return admin.messaging().sendToDevice(tokens, payload).then(response => { response.results.forEach((result, index) => { console.log('FcmToken: ', tokens); const error = result.error; if (error) { console.log('Error Occured:', error); } }); console.log('User Liked'); return null; // Added return }); }); } if (type=='Follow') { const followerUserId = snap.val().BY_USER_NODE_NAME; const followeeUserId = snap.val().FOLLOWING_USER_NODE_NAME; const followerUserName = snap.val().BY_USER_NAME; const followerPhotoUrl = snap.val().BY_USER_PHOTO_URL; var followerUserRef = db.ref('USER_MANAGEMENT/USERS/'+followerUserId); var followeeUserRef = db.ref('USER_MANAGEMENT/USERS/'+followeeUserId); const followeeFollowingRef = db.ref('USER_MANAGEMENT/FOLLOWING/'+followeeUserId+'/'+followerUserId); return Promise.all([followeeUserRef.once('value')]).then(function(snaps) { var data = snaps[0].val(); const fcmToken = data.FCM_TOKEN; // Return inner Promise chain return followeeFollowingRef.once('value').then(function(followeeSnapshot) { let isFollow = followeeSnapshot.exists() ? 'YES' : 'NO'; console.log(`FOLLOW ${isFollow}`); const payload = { notification: { title: '珞 You have a new follower!', body: `${followerUserName} is now following you.`, sound: 'default', icon: '', byUserId: followerUserId, byUserName: followerUserName, type: 'Follow', isFollow: isFollow, byUserPhotoUrl: followerPhotoUrl, badge : '1' } }; const tokens = fcmToken; console.log('FcmToken: ', tokens); return admin.messaging().sendToDevice(tokens, payload).then(response => { response.results.forEach((result, index) => { const error = result.error; if (error) { console.log('Error Occured:', error); } }); console.log('User Followed'); return null; // Added return }); }); }); } // Default return for unhandled types return null; });
Older Firebase Function versions didn't enforce this ESLint rule as strictly, which is why your code worked before. These fixes ensure all Promise chains are properly closed, so Firebase knows when your function is done executing.
内容的提问来源于stack exchange,提问作者Randima Lahiru

