You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

非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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 11:36:05