非async函数竞态问题:如何等待jsmediatags.read回调完成后返回结果
解决方案
核心思路是将回调风格的jsmediatags.readAPI手动包装为Promise,即可通过await或者.then等待异步执行完成后再操作返回结果,避免提前读取未赋值的字段。
第一步:重构get_song函数,返回Promise实例
const get_song = (song_path, album) => { return new Promise((resolve, reject) => { const song = { title: null, // 其他需要的song字段可在此处补充定义 }; jsmediatags.read(song_path, { onSuccess: function (tag) { song.title = tag?.tags?.title; console.info("set song fields", song.title); // 异步执行完成后返回完整song对象 resolve(song); }, onError: function (error) { console.error("读取音频元数据失败", error); // 可根据业务需求选择reject抛出错误,或者resolve带默认值的song对象 reject(error); } }); }); }
第二步:调用时等待Promise执行完成后再做序列化/发送操作
有两种常用调用方式,根据你的代码场景选择即可:
方式1:async/await写法(推荐,代码更易读)
注意await必须在被async修饰的函数内部使用:
// 示例调用函数 const processSong = async () => { try { // 等待get_song执行完成,拿到的song对象已经完成所有字段赋值 const song = await get_song("示例音频路径.mp3", "示例专辑"); console.info("return from get_song", song.title); // 在这里执行序列化、发送数据等操作即可 const serializedSong = JSON.stringify(song); // 后续发送逻辑... } catch (err) { // 处理读取失败的异常场景 console.error("获取歌曲信息失败", err); } }
方式2:.then链式调用写法
get_song("示例音频路径.mp3", "示例专辑") .then(song => { console.info("return from get_song", song.title); // 序列化、发送数据逻辑写在此处 const serializedSong = JSON.stringify(song); // 后续发送逻辑... }) .catch(err => { // 处理读取失败的异常场景 console.error("获取歌曲信息失败", err); })
原问题原因说明
你之前的写法直接同步返回了初始化的song对象,而jsmediatags.read的回调是异步执行的,会在同步代码全部跑完之后才触发,所以出现了返回时title还未赋值的问题。包装为Promise后,只有当回调执行完成才会向外返回结果,从根源上避免了提前读取未赋值字段的问题。
内容的提问来源于stack exchange,提问作者nlta
相关产品推荐
相关产品推荐

