JavaScript跨函数访问对象遇异常:空对象或Promise <pending> 排查
问题分析与解决方案
你的问题核心在于异步代码的执行顺序以及全局变量的时机问题,咱们一步步拆解清楚:
为什么会得到空对象或Promise { <pending> }?
- 执行顺序错位:你同步调用了
getMessageData(),这时候getNotifications()还没开始执行(或者还在等待fcmTokens()的异步结果返回),所以messageData还是初始的空对象{}。 - 异步赋值的延迟性:哪怕
getNotifications()启动了,await fcmTokens()是异步操作,得等它完成后才会进入forEach给messageData赋值,而getMessageData()早就在这之前执行完了,自然拿不到赋值后的结果。 - 额外小问题:你的
forEach里每次把messageData直接赋值为notificationData,最后messageData只会保留fcmObjects的最后一个元素,这大概率不是你想要的(如果想收集所有数据,应该用数组或者键值对形式存储)。
修正方案(推荐避免全局变量,用异步函数返回结果)
方案1:让getNotifications返回数据,在then中处理
去掉全局变量,让异步函数直接返回需要的数据,然后在它的then回调里调用处理逻辑:
const getNotifications = async () => { let fcmObjects = await fcmTokens(); // 如果要收集所有数据,这里用数组示例(可根据需求改成对象) return fcmObjects; }; function getMessageData(data) { console.log(data); } // 先执行异步函数,拿到结果后再调用处理函数 getNotifications() .then((messageData) => { getMessageData(messageData); console.log('All Done'); }) .catch((error) => { console.log('Oops', error); });
方案2:用async/await包裹执行逻辑(更直观)
如果你的执行环境支持顶级await(比如现代浏览器、Node.js 14.8+),可以这样写:
const getNotifications = async () => { let fcmObjects = await fcmTokens(); return fcmObjects; }; async function main() { try { const messageData = await getNotifications(); console.log(messageData); // 直接在这里处理数据 console.log('All Done'); } catch (error) { console.log('Oops', error); } } main();
如果你一定要用全局变量(不推荐,易引发时序问题)
那必须确保在getNotifications执行完成后再调用getMessageData:
var messageData = []; // 改成数组存储所有数据,避免覆盖 const getNotifications = async () => { let fcmObjects = await fcmTokens(); fcmObjects.forEach((notificationData) => { messageData.push(notificationData); // 用push添加,而非直接覆盖 }); }; function getMessageData() { console.log(messageData); } // 等异步操作完成后再调用处理函数 getNotifications() .then(() => { getMessageData(); console.log('All Done'); }) .catch((error) => { console.log('Oops', error); });
关键总结
- 尽量避免用全局变量存储异步获取的数据,因为异步操作的时序很难控制,容易出现数据未就绪的情况。
- 异步函数的结果最好通过
return返回,然后用then或者await来获取,保证代码执行顺序符合预期。
内容的提问来源于stack exchange,提问作者sk123
相关产品推荐
相关产品推荐

