【问题标题】:There is a function with a promise. Inside this function I call this function again (recursion). How to wait till recursed promise is resolved?有一个带有承诺的功能。在这个函数中,我再次调用这个函数(递归)。如何等到递归承诺解决?
【发布时间】:2018-07-31 12:42:29
【问题描述】:

我需要一个接一个地运行 2 个函数:getUserPlaylists(接收播放列表)和 getPlaylistTracks(接收提供的播放列表的曲目)。

一个响应最多可以有 50 首曲目,所以如果我想获取其余曲目,我需要使用 PageToken。问题是我不能让递归函数getPlaylistTracks 等到递归完成。

function getPlaylistsWithTracks () {
  return new Promise((resolve, reject) => {
    getUserPlaylists()
      .then(function (playlists) {

        playlists.forEach(
          async function (playlistObj) {
            await getPlaylistTracks(playlistObj).then(function (tracks) {
              playlistObj['tracks'] = tracks
            })
          })

        console.log('resolve')
        resolve(playlists)
      })
  })
}

function getPlaylistTracks (playlistObj, pageToken) {
  return new Promise((resolve, reject) => {

    let playlistTracks = []

    let requestOptions = {
      'playlistId': playlistObj['youtubePlaylistId'],
      'maxResults': '50',
      'part': 'snippet'
    }

    if (pageToken) {
      console.log('pageToken:', pageToken)
      requestOptions.pageToken = pageToken
    }

    let request = gapi.client.youtube.playlistItems.list(requestOptions)

    request.execute(function (response) {
      response['items'].forEach(function (responceObj) {
        let youtubeTrackTitle = responceObj.snippet.title

        if (youtubeTrackTitle !== 'Deleted video') {
          let youtubeTrackId = responceObj.snippet.resourceId.videoId

          playlistTracks.push({
            youtubePlaylistId: playlistObj.playlistId,
            youtubePlaylistTitle: playlistObj.playlistTitle,
            youtubeTrackId: youtubeTrackId,
            youtubeTrackTitle: youtubeTrackTitle,
          })
        }

      })

      // Here I need to wait a bit
      if (response.result['nextPageToken']) {
        getPlaylistTracks(playlistObj, response.result['nextPageToken'])
          .then(function (nextPageTracks) {
            playlistTracks = playlistTracks.concat(nextPageTracks)
          })
      }

    })

    resolve(playlistTracks)

  })
}

getPlaylistsWithTracks()

在我的控制台中,我看到了下一个:

> resolve
> pageToken: 123
> pageToken: 345

但是,我想看resolve最后一个。

如何等待递归执行?

【问题讨论】:

  • 将解析调用放入请求响应中
  • @Occam'sRazor,没有帮助。控制台中的顺序仍然相同(resolve 第一个,然后是pageTokens)
  • Here I need to wait a bit - 你需要在 .then 里面解析 ... 在没有 nextPageToken 的情况下解析应该在 else 块中完成

标签: javascript recursion promise es6-promise


【解决方案1】:

正确避免Promise constructor antipattern(don't) use forEach with async functions

此外,递归并没有什么特别之处。这就像您想要等待的任何其他返回承诺的函数调用一样 - 将其放入您的 then 链或 await 中。 (后者要容易得多)。

async function getPlaylistsWithTracks() {
  const playlists = await getUserPlaylists();
  for (const playlistObj of playlists) {
    const tracks = await getPlaylistTracks(playlistObj);
    playlistObj.tracks = tracks;
  }
  console.log('resolve')
  return playlists;
}

async function getPlaylistTracks(playlistObj, pageToken) {
  let playlistTracks = []
  let requestOptions = {
    'playlistId': playlistObj['youtubePlaylistId'],
    'maxResults': '50',
    'part': 'snippet'
  }
  if (pageToken) {
    console.log('pageToken:', pageToken)
    requestOptions.pageToken = pageToken
  }
  let request = gapi.client.youtube.playlistItems.list(requestOptions)
  const response = await new Promise((resolve, reject) => {
    request.execute(resolve); // are you sure this doesn't error?
  });

  response['items'].forEach(function (responceObj) {
    let youtubeTrackTitle = responceObj.snippet.title
    if (youtubeTrackTitle !== 'Deleted video') {
      let youtubeTrackId = responceObj.snippet.resourceId.videoId
      playlistTracks.push({
        youtubePlaylistId: playlistObj.playlistId,
        youtubePlaylistTitle: playlistObj.playlistTitle,
        youtubeTrackId: youtubeTrackId,
        youtubeTrackTitle: youtubeTrackTitle,
      })
    }
  })
  if (response.result['nextPageToken']) {
    const nextPageTracks = await getPlaylistTracks(playlistObj, response.result['nextPageToken']);
    playlistTracks = playlistTracks.concat(nextPageTracks);
  }
  return playlistTracks;
}

【讨论】:

  • 它现在可以工作了,但比以前慢了大约 10-15 倍。是因为异步\等待吗?速度可以提高吗?
  • 这是因为getPlaylistsWithTracks 中的循环现在是连续的,一切都在等待。有关如何同时向轨道发出请求,请参阅我的答案中的第二个链接。
  • 现在我看到了正确的模式。非常感谢您的帮助和有用的链接!已编辑:我根据您的链接中的解决方案更改了循环,并恢复了速度。再次感谢:)
猜你喜欢
  • 2014-06-30
  • 2015-12-05
  • 2017-05-09
  • 1970-01-01
  • 1970-01-01
  • 2018-12-01
  • 2016-12-23
  • 1970-01-01
  • 2019-05-27
相关资源
最近更新 更多