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

Node.js中Spotify Web API异步调用顺序问题及解决方法

搞定Spotify API异步执行顺序问题

哥们,你踩中了Node.js异步编程的经典坑——你的authorize()是异步函数,但你调用它的时候没等它跑完,后面的API请求直接就冲出去了,这时候access token还没设置好,请求肯定失败啊!

别慌,咱们一步步改,核心就是确保setAccessToken执行完再调用后续API,具体方案如下:

核心修改点:用await等待异步授权完成

因为authorize()是async函数,它内部的await spotifyApi.authorizationCodeGrant(code)是异步操作,你直接调用authorize()的话,它会立刻返回一个Promise,代码会继续往下走,根本不等授权和token设置完成。

所以我们需要做两个关键修改:

  1. 把路由回调函数改成async函数:这样才能在回调里使用await关键字;
  2. 用await等待authorize()执行完毕:让代码暂停在这里,等token设置好再继续执行后续API请求。

修改后的完整代码

app.get('/callback', async (req, res) => { // 改成async函数
  var code = req.query.code || null;
  if (code === null) {
    console.log("code is null");
  }

  async function authorize() {
    const data = await spotifyApi.authorizationCodeGrant(code);
    accesToken = data.body['access_token']; // 这里注意拼写,是不是应该是accessToken?
    refreshToken = data.body['refresh_token'];
    spotifyApi.setAccessToken(accesToken);
    spotifyApi.setRefreshToken(refreshToken);
  }

  try {
    await authorize(); // 这里加await,等待授权和token设置完成
  } catch (err) {
    console.log('Something went wrong during authorization!', err);
    return res.redirect('/error'); // 可以加个错误跳转,避免继续执行后面的代码
  }

  // 现在这里的API请求肯定能拿到已设置好的access token了
  spotifyApi.getMySavedTracks({ limit : lim, offset: 1 })
    .then(function(data) {
      return data.body.items;
    }, function(err) {
      console.log('Failed to get saved tracks!', err);
    })
    .then(function(items) {
      let ids = [];
      items.forEach(function(item) {
        ids.push(item.track.id);
      })
      return spotifyApi.getAudioFeaturesForTracks(ids);
    })
    .then(function(data) {
      let songs = data.body.audio_features;
      let filteredSongURIs = [];
      songs.forEach(function(song) {
        if ((song.energy >= moodScore-offset) && (song.energy <= moodScore+offset)) {
          filteredSongURIs.push(song.uri);
        }
      })
      // 创建播放列表并添加歌曲
      return spotifyApi.createPlaylist('Mooder Playlist', {
        'description': 'My description',
        'public': true
      })
      .then(function(data) {
        return data.body.id;
      }, function(err) {
        console.log('Failed to create playlist!', err);
      })
      .then(function(playlist) {
        return spotifyApi.addTracksToPlaylist(playlist, filteredSongURIs);
      })
      .then(function(data) {
        console.log('Added tracks to playlist!');
      }, function(err) {
        console.log('Failed to add tracks to playlist!', err);
      });
    }, function(err) {
      console.log(err);
    });

  res.redirect('/testAPI');
});

额外优化建议(可选)

如果你觉得链式then看起来有点绕,可以把整个API请求部分也改成async/await风格,代码会更清晰:

// 替换掉原来的链式then部分
try {
  // 获取收藏的歌曲
  const savedTracksData = await spotifyApi.getMySavedTracks({ limit : lim, offset: 1 });
  const items = savedTracksData.body.items;

  // 提取歌曲ID
  const ids = items.map(item => item.track.id);

  // 获取音频特征
  const audioFeaturesData = await spotifyApi.getAudioFeaturesForTracks(ids);
  const songs = audioFeaturesData.body.audio_features;

  // 过滤符合条件的歌曲
  const filteredSongURIs = songs.filter(song => 
    song.energy >= moodScore - offset && song.energy <= moodScore + offset
  ).map(song => song.uri);

  // 创建播放列表
  const playlistData = await spotifyApi.createPlaylist('Mooder Playlist', {
    'description': 'My description',
    'public': true
  });
  const playlistId = playlistData.body.id;

  // 添加歌曲到播放列表
  await spotifyApi.addTracksToPlaylist(playlistId, filteredSongURIs);
  console.log('Added tracks to playlist!');
} catch (err) {
  console.log('API request failed!', err);
}

这样代码的执行顺序一目了然,错误处理也更集中。

关键知识点回顾

  • async函数总是返回一个Promise;
  • await关键字只能在async函数内部使用,它会暂停代码执行,直到后面的Promise完成;
  • 异步操作如果不等待,代码会按顺序继续执行,导致依赖异步结果的后续操作出错。

内容的提问来源于stack exchange,提问作者Khashhogi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 07:45:34