我正在尝试通过soundcloud API下载曲目,然后在下载了不确定数量的曲目后启动回调。当我运行下面的代码时,即使我打算将它做为最后一件事,也可以在控制台上看到“所有完成”的日志,这是我的错。

// Deps
import fs from 'fs'
import SC from 'node-soundcloud'
import request from 'request'

// Write mp3 function
function writeMP3(track) {
  return new Promise((resolve, reject) => {

    console.log('Starting download: ', track.title)

    request.get(track.download_url)
    .on('error', err => {
      // reject('Download error: ', err)
    })
    .on('finish', () => {
      () => resolve('Download complete')
    })
    .pipe(fs.createWriteStream(`./data/temp/${track.title}_${track.user.username}.mp3`))

  })
}

async function asyncTrackFetch(track) {
  return await writeMP3(track)
}

// Array of promises to callback upon
const trackActions = []

SC.init({
  id: 'MY_ID',
  secret: 'MY_SECRET'
})

SC.get('/tracks', (err, tracks) => {

  if (err) {
    throw new Error(err)
  } else {

    console.log('Tracks fetched: ', tracks.length)

    tracks.map(track => {

      if (track.downloadable) {
        console.log('downloadable')

        trackActions.push(asyncTrackFetch(track))

      }

    })
  }
})

// Perform requests async
Promise.all(trackActions).then(() => {
  console.log('All done')
  console.log(fs.readdirSync('./data/temp'))
})

最佳答案

Promise.all(trackActions)等待trackActions中的任何承诺,但在您拨打电话时trackActions为空。您仅在调用SC.get回调后才向数组添加promise。

尝试将您的Promise.all...块放入SC.get回调中,如下所示:

SC.get('/tracks', (err, tracks) => {

  if (err) {
    throw new Error(err)
  } else {

    console.log('Tracks fetched: ', tracks.length)

    tracks.map(track => {

      if (track.downloadable) {
        console.log('downloadable')

        trackActions.push(asyncTrackFetch(track))

      }

    })

    Promise.all(trackActions).then(() => {
      console.log('All done')
      console.log(fs.readdirSync('./data/temp'))
    })
  }
})


同样值得一提的是,您的行throw new Error(err)将使程序崩溃,因为没有地方可以捕获该错误。

正如Antonio Val所提到的,有更好的方法可以做到这一点。如果您将node-soundcloud库设为promis,那么代码的最后部分可能如下所示:

SC.get('/tracks').then(tracks => {
  // No need for trackedActions array.
  return Promise.all(tracks.filter(track => track.downloadable)
    .map(track => asyncTrackFetch(track)))
}).then(fetchedTracks => {
  console.log('All done fetching tracks', fetchedTracks)
}).catch(err => {
  // Handle error.
})


或在async function内,

try {
  const tracks = await SC.get('/tracks')
  const fetchPromises = tracks
    .filter(track => track.downloadable)
    .map(track => asyncTrackFetch(track))
  const fetchedTracks = await Promise.all(fetchPromises)

  console('All done fetching tracks.', fetchedTracks)
} catch (err) {
  // Handle error
}

07-26 03:42