Node.js函数如何返回数据库读取数组并支持Promise调用
解决异步获取FCM Token数组的问题
你的问题核心在于同步循环里的异步操作没有被等待,导致函数提前返回了空数组。我们需要把loadTokens改成返回一个Promise,让它等待所有数据库查询完成后再返回填充好的token数组。
修改后的loadTokens函数
function loadTokens(userIds) { // 将每个userId转换为获取对应token的Promise const tokenPromises = userIds.map(item => { return admin.database().ref('/users/' + item).once('value') .then(snapShot => { const user = snapShot.val(); console.log('User', user.name); console.log('token', user.fcmToken); // 返回当前用户的fcmToken,Promise.all会自动收集这些值 return user.fcmToken; }); }); // 等待所有异步查询完成,返回包含完整token数组的Promise return Promise.all(tokenPromises); }
关键修改点说明
用
map替代forEach:forEach只是同步遍历数组,不会处理异步操作的返回值;而map会把每个userId对应的异步查询Promise收集成一个数组,方便后续用Promise.all处理。Promise.all的作用:
这个方法会等待传入的所有Promise都成功完成,然后返回一个新的Promise——它resolve的值就是所有异步操作返回值组成的数组(也就是你需要的tokens数组)。直接返回Promise:
现在loadTokens不再直接返回空数组,而是返回Promise.all的结果,这样外部调用时就能通过.then拿到填充好的数组。
调用代码无需修改(直接兼容)
你原来的调用代码完全可以正常工作,因为现在loadTokens返回的是Promise,.then里的tokens参数就是完整的token数组:
return loadTokens(userIds).then(tokens => { console.log('tokens', tokens); // 这里能拿到所有有效的fcmToken return admin.messaging().sendToDevice(tokens, payload); });
可选优化:过滤无效Token
如果存在用户没有fcmToken或者用户不存在的情况,可以在异步查询里过滤掉无效值,避免传入空token:
function loadTokens(userIds) { const tokenPromises = userIds.map(item => { return admin.database().ref('/users/' + item).once('value') .then(snapShot => { const user = snapShot.val(); // 检查用户是否存在且有fcmToken if (!user || !user.fcmToken) { console.log(`用户 ${item} 不存在或无FCM Token`); return null; } console.log('User', user.name); console.log('token', user.fcmToken); return user.fcmToken; }); }); // 等待所有操作完成后过滤掉null值 return Promise.all(tokenPromises).then(tokens => tokens.filter(token => token != null)); }
这样最终得到的tokens数组只会包含有效的FCM Token,避免调用sendToDevice时出现错误。
内容的提问来源于stack exchange,提问作者holparb
相关产品推荐
相关产品推荐

