如何选择一个事件监听器,让我等待异步.times完成后再运行一个函数。

13
我正在使用一个node.js服务器,Spotify API和spotify-web-api-js节点模块来创建一个Web应用程序,用户可以输入艺术家的名称,查看相关艺术家的歌曲列表,然后选择将该播放列表保存到他们自己的Spotify帐户。但是,我仍然在最后一步遇到麻烦。
我的用户授权流程首先发生:
if (params.access_token) {

    s.setAccessToken(params.access_token);

    s.getMe().then(function(data) {

      console.log(data);
      console.log(data.id);
      user_id = data.id;

以下是API收集歌曲实际细节的位置。虽然它在下面,但它是首先发生的,只有当用户在该页面上点击第二个按钮时才进行用户授权。
async.times(counter, function(n, next){
        s.getArtistTopTracks(relatedArtists[n].id, "US", function (err, data2) {
          relatedArtists[n].song = data2.tracks[0].name;
          relatedArtists[n].uri = data2.tracks[0].uri;
          console.log(relatedArtists[n].uri);
          // make sure to put the access token here add song to playlist
          // create array
          song_uris.push(relatedArtists[n].uri);
          console.log(song_uris);

          // song_uris = relatedArtists[n].uri;
          //
          // console.log(song_uris);

          next(null);

      $("#playlist").load(function() {
            s.addTracksToPlaylist(user_id, playlist_id, song_uris);
          });
        });


      }, function(err) {
        // console.table(relatedArtists);

        for (k = 0; k < 20; k++)
        {
          $('#related-artist').append('<p><strong>' + relatedArtists[k].name + '</strong> -- \"' + relatedArtists[k].song + '\"</p>');


        }

(这里是完整代码的JSBin, 尽管可能无法运行,因为我在自己的服务器上使用browserify)

现在,在第114行,我使用async.times将内容推入一个数组song_uris.push(relatedArtists[n].uri);。由于这是在第66行创建播放列表之后,所以它显示为空数组:

 s.createPlaylist(user_id, {name: 'Related Artist Playlist'}).then(function(data3) {
        console.log(data3);
        playlist_id = data3.uri;
        playlist_id = playlist_id.substring(33);
        console.log(playlist_id);


        console.log(song_uris);


       });

在这里,console.log(song_uris)显示一个空数组,因此addTracksToPlaylist()会停止工作:

enter image description here

另一方面,如果我尝试在下面使用addTracksToPlaylist(),我没有权限访问用户的帐户。
在基本功能(显示歌曲列表)已经工作后,用户授权流程已被添加,但我不确定如何有效地重构它以便将该列表保存到我的用户播放列表中。目前,我只在Spotify帐户中创建了一个空白播放列表。
我应该添加什么样的事件监听器,以便它将等待每个async.times实例都执行完毕,以便addTracksToPlaylist()可以正常工作?DOM已经在获取这些数据之前初始化加载。我查看了this question,但它并没有帮助我解决这个问题。谢谢!
编辑:我现在已经按照需要创建了song_uri数组,但我仍然无法将其添加到播放列表中。我一直在调整我的访问令牌位置,以便可以访问所创建的播放列表,但仍然没有成功。

第130行的console.log(song_uris);语句显示了我需要的完整数组,但是当我将其插入到s.addTracksToPlaylist(user_id, playlist_id, song_uris);中时,在开发者控制台中出现了以下错误:

POST https://api.spotify.com/v1/users/tenderoni-/playlists/7MtQTzUsxD4IEJ8NmmE36q/tracks?uris= 400 (Bad Request)
bundle.js:10616
Uncaught (in promise) XMLHttpRequest {}

基本上,由于某种原因它没有接收到参数。我事先记录了playlist_id,所以我可以知道它正在工作(此外,我在我的Spotify帐户中看到了指定标题的空白播放列表被创建)。
完整的更新代码在这里:https://github.com/yamilethmedina/cs50xmiami/blob/master/assignments/portfolio/public/scripts.js

你是否打算在JSBin帖子中包含凭据?我无法确定这些是来自某个API文档还是你自己的。 - W. Cybriwsky
1个回答

2

async.times 的回调参数可以带有第二个 'results' 参数,因此如果您在循环的每一轮中使用 'next' 和 song_uri 调用它,你最终可以得到 song_uris,通过 searchArtists 传递一个回调,并在那里使用它。以下是这个方案的简单版本:

$(document).ready(function($) {
    $('#s').on('submit', function() {
        searchArtists($('#originalartist').val(), function(err, song_uris) {
            if (params.access_token) {
                // omitted
                s.setAccessToken(params.access_token);
                s.getMe().then(function(data) {
                    console.log(data);
                    console.log(song_uris);
                });
            }
        });
        return false;
    });
})

function searchArtists(originalArtist, callback) {
    s.getArtistRelatedArtists(originalArtistId, function(err, data) {
        async.times(counter, function(n, next) {
            // omitted
            next(related_artists[n].uri)
        }, function(err, song_uris) {
            callback(err, song_uris);
        });

    });

}

s.createPlaylist()会放在第一部分,在getMe()函数内吗? - Yami Medina
是的,因为你仍然需要从getMe()回调中获取user_id才能调用s.createPlaylist()。由于getMe()已经在searchArtists的回调函数中,你也可以访问song_uris。 - W. Cybriwsky
我注意到它从getArtistRelatedArtists()跳到async.times()。getArtistTopTracks()不应该在这两行之间吗?我通过该函数获取每个相关艺术家的第一首歌曲,以填充song_uris。我认为我应该回到我的初始代码,然后再尝试实现这个功能,因为我认为我可能已经搞砸了其他东西,打破了在屏幕上打印播放列表的for循环,歌曲在浏览器中显示为未定义,但在控制台中没有问题,而且虽然我看到有流量访问account.spotify.com,但我再也没有控制台响应了。 - Yami Medina
getArtistTopTracks() 将像之前一样在 async.times() 回调函数中,如果删除它会使事情变得不太清晰,对此表示抱歉。 - W. Cybriwsky
在聊天中我没有收到你的回复?这是代码的最新版本:http://codetidy.com/7215 在 next(relatedArtists[n].uri); 之后似乎没有任何运行。 我尝试将s.addTracksToPlaylist(user_id, playlist_id, song_uris);放置在不同的位置,但似乎没有效果。 - Yami Medina
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接