Node.js 什么';使用async Wait有什么不对?

Node.js 什么';使用async Wait有什么不对?,node.js,asynchronous,async-await,es6-promise,ecmascript-2017,Node.js,Asynchronous,Async Await,Es6 Promise,Ecmascript 2017,我试图通过SoundCloudAPI下载曲目,然后在下载了不确定数量的曲目后启动回调。当我运行下面的代码时,我看到“全部完成”被记录在控制台日志中,而不是其他任何东西,尽管我希望它是最后一件事。。。我做错了什么 // Deps import fs from 'fs' import SC from 'node-soundcloud' import request from 'request' // Write mp3 function function writeMP3(track) { r

我试图通过SoundCloudAPI下载曲目,然后在下载了不确定数量的曲目后启动回调。当我运行下面的代码时,我看到“全部完成”被记录在控制台日志中,而不是其他任何东西,尽管我希望它是最后一件事。。。我做错了什么

// 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
tracks.map
循环完成之后

一个更优雅的解决方案是promisify
SC.get
,并在所有代码中使用
async wait

更新:

无法测试它,所以不确定它是否有效,但它可能是这样的:

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

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`))

  })
}

function getTracks() {
  return new Promise((resolve, reject) => {

    SC.get('/tracks', (err, tracks) => {
      if (err) {
        return reject(err)
      }

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

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))

      }

    })

    Promise.all(trackActions).then(() => {
      console.log('All done')
      console.log(fs.readdirSync('./data/temp'))
    })
  }
})
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 start() {
  const tracks = await getTracks();

  for (let track of tracks) {
    await writeMP3(track)
  }
}

start()
.then(() => {
  console.log('All done')
  console.log(fs.readdirSync('./data/temp'))
})
.catch((err) => {
  // insert error handler here
})
如果您只想使用承诺:

getTracks
.then((tracks) => {
  const promiseArray = tracks.map((track) => {
    return writeMP3(track)
  })
  return Promise.all(promiseArray)
})
.then(() => {
  console.log('All done')
  console.log(fs.readdirSync('./data/temp'))
})
.catch((err) => {
  // insert error handler here
})
Promise.all(trackActions)
等待
trackActions
中的任何承诺,但在您呼叫时,
trackActions
为空。只有在调用了
SC.get
回调之后,才能向数组中添加承诺

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

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

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`))

  })
}

function getTracks() {
  return new Promise((resolve, reject) => {

    SC.get('/tracks', (err, tracks) => {
      if (err) {
        return reject(err)
      }

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

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))

      }

    })

    Promise.all(trackActions).then(() => {
      console.log('All done')
      console.log(fs.readdirSync('./data/temp'))
    })
  }
})
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.
})
同样值得一提的是,您的行
抛出新错误(err)
将使程序崩溃,因为没有地方可以捕获该错误

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

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

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`))

  })
}

function getTracks() {
  return new Promise((resolve, reject) => {

    SC.get('/tracks', (err, tracks) => {
      if (err) {
        return reject(err)
      }

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

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))

      }

    })

    Promise.all(trackActions).then(() => {
      console.log('All done')
      console.log(fs.readdirSync('./data/temp'))
    })
  }
})
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.
})
或者在一个


SC.get('/tracks',…
是一个回调函数,您不需要等待它的解析,然后才能执行Promise.all。您需要手动做出一个在
(err,tracks)=>{…}
内解析的承诺,然后在执行
Promise.all(trackActions)之前等待它的解析
啊,明白了。谢谢!我完全忘记了API操作当然是异步的…@meirionhoughes知道如何编写它,因为文件编写是通过流
管道进行的
?我无法理解这一点。