在下面的readFile代码中如何使用Promise.all?

时间:2018-09-06 12:35:42

标签: javascript promise es6-promise

在下面的代码中,我正在读取一些文件,并获取它们的文件名和文本。之后,我将数据存储在一个选项变量中以生成一个epub文件:

const Epub = require("epub-gen")
const folder = './files/'
const fs = require('fs')
let content = []

fs.readdir(folder, (err, files) => {
  files.forEach(filename => {
    const title = filename.split('.').slice(0, -1).join('.')
    const data = fs.readFileSync(`${folder}${filename}`).toString('utf-8')
    content.push({ title, data })
  })
})

const option = {
  title: "Alice's Adventures in Wonderland", // *Required, title of the book.
  content
}

new Epub(option, "./text.epub")

问题是new Epub在读取文件之前,content准备就绪之前运行。我认为Promise.all是这里的合适人选。我检查了Mozilla文档。但这显示了各种承诺,但我没有。因此,我不太确定如何在此处使用Promise.all

有什么建议吗?

3 个答案:

答案 0 :(得分:2)

您的问题出在readdir上,它是异步的,因此new Epub就像您已经知道的那样,被称为 before ,它是callback参数。

readdirSync之后,切换为使用const option ... new Epub...或在callback的{​​{1}}参数内移动readdir

答案 1 :(得分:1)

向数组添加promise。每个承诺都应以您推向content

的价值来解决

当所有诺言都解决时,返回的值将是先前称为content的数组。

此外,您可以并且应该使用所有异步fs调用。因此readFileSync可以替换为readFile(异步)。但是,我没有用此异步调用替换您的代码,因此您可以清楚地看到回答原始问题所需的内容。

不确定我是否在代码段中正确嵌套了。

const Epub = require("epub-gen")
const folder = './files/'
const fs = require('fs')

let promises = []

fs.readdir(folder, (err, files) => {
  files.forEach(filename => {
    promises.push(new Promise((resolve, reject) => {

      const title = filename.split('.').slice(0, -1).join('.')
      const data = fs.readFile(`${folder}${filename}`).toString('utf-8')
      resolve({
        title,
        data
      })

    }))
  })
})

const option = {
  title: "Alice's Adventures in Wonderland", // *Required, title of the book.
  content
}

new Epub(option, "./text.epub")

Promise.all(promises).then((content) => {
  //done
})

答案 2 :(得分:1)

由于您使用readFileSync,因此您现在可以同步进行所有操作。 因此,您可以将Epub创建的内容放置在forEach循环之后。

如果要异步,我的第一个问题是:

您的node.js版本是否支持util.promisify(节点版本8.x或更高版本的iirc)? 如果是这样,则可以用来将诸如readFile之类的回调函数转换为Promise。如果没有,则可以使用相同的逻辑,但是可以像其他解决方案一样使用嵌套的回调。

const FS = require( 'fs' );
const { promisify } = require( 'util' );
const readFile = promisify( FS.readFile );
const readFolder = promisify( FS.readFolder );

readFolder( folder )
  // extract the file paths. Maybe using `/${filename}` suffices here.
  .then( files => files.map( filename => `${folder}${filename}`))
  // map the paths with readFile so we get an array with promises.
  .then( file_paths => file_paths.map( path => readFile( path )))
  // fecth all the promises using Promise.all() .
  .then( file_promises => Promise.all( file_promises ))
  .then( data => {
    // do something with the data array that is returned, like extracting the title.
    // create the Epub objects by mapping the data values with their titles
  })
  // error handling.
  .catch( err => console.error( err ));