1

我正在创建一个将多个降价文件转换为单个 pdf 的过程。它为在源目录中找到的每个 .md 文件创建一个 pdf 文件。然后它将单个 pdf 文件合并为一个 pdf。正是这最后一步未能说明单个 pdf 文件不存在。

const markdownpdf = require('markdown-pdf')
const path = require('path')
const PDFMerge = require('pdf-merge')
const fse = require('fs-extra')

const srcDir = '../manuscript'
const outDir = 'out'

const main = () => {

    fse.pathExists(outDir)
    .then(() => {
      fse.remove(outDir).then(() => {
        fse.ensureDir(outDir)
      }).then(() => {
        return fse.readdir(srcDir)
      }).then((srcDirFiles) => {
        console.log('source directory file count = ', srcDirFiles.length)
        return srcDirFiles.filter(f => path.extname(f) === '.md')
      }).then((mdFiles) => {
        console.log('number of md files', mdFiles.length);
        return mdFiles.map(file => {

          const outFileName = `${path.basename(file, '.md')}.pdf`
          fse.createReadStream(`${srcDir}/${file}`)
            .pipe(markdownpdf())
            .pipe(fse.createWriteStream(`${outDir}/${outFileName}`))
          return `${outDir}/${outFileName}`
        })
      }).then(outFiles => {
        console.log('number of pdf files created =', outFiles.length)
        PDFMerge(outFiles, { output: `${__dirname}/3.pdf`  })
      })
    })
}

main()

如果我将 PDFMerge() 行包装在 setTimeout() 中,它确实有效

setTimeout(() => {
  PDFMerge(outFiles, { output: `${__dirname}/3.pdf` })
}, 1000)

我想知道为什么需要 setTimeout() 以及需要更改哪些内容,所以不需要。

我还写了一个 async/await 版本,它有同样的问题,也可以使用 setTimeOut()

编辑

响应 Zach Holt 的建议,这里是 async/await 版本:

const markdownpdf = require('markdown-pdf')
const path = require('path')
const PDFMerge = require('pdf-merge')
const fse = require('fs-extra')

const srcDir = '../manuscript'
const outDir = 'out'

const createPdf = async (file) => {
  try {
    const outFileName = `${path.basename(file, '.md')}.pdf`
    await fse.createReadStream(`${srcDir}/${file}`)
      .pipe(markdownpdf())
      .pipe(await fse.createWriteStream(`${outDir}/${outFileName}`))
  }
  catch (e) {
    console.log(e)
  }
}

const makePdfFiles = (files) => {
  files.forEach(file => {
    if (path.extname(file) === '.md') {
      createPdf(file)
    }
  })
}

const mergeFiles = async (files) => {
  try {
    await PDFMerge(files, {output: `${__dirname}/3.pdf`})
  }
  catch (e) {
    console.log(e)

  }
}

const addPathToPdfFiles = (files) => {
  return files.map(file => {
    return `${outDir}/${file}`
  })
}

const main = async () => {
  try {
    const exists = await fse.pathExists(outDir)
    if (exists) {
      await fse.remove(outDir)
    }
    await fse.ensureDir(outDir)
    const mdFiles = await fse.readdir(srcDir)
    const filesMade = await makePdfFiles(mdFiles)
    const pdfFiles = await fse.readdir(outDir)
    const pdfFilesWithPath = addPathToPdfFiles(pdfFiles)
    mergeFiles(pdfFilesWithPath)
    // setTimeout(() => {
    //   mergeFiles(pdfFilesWithPath)
    // }, 1000)
  } catch (e) {
    console.log(e)
  }
}

它有同样的问题。

我也试过:

const makePdfFiles = files => {
  return new Promise((resolve, reject) => {
    try {
      files.forEach(file => {
        if (path.extname(file) === '.md') {
          createPdf(file)
        }
      })
      resolve(true)
    } catch (e) {
      reject(false)
      console.log('makePdfFiles ERROR', e)
    }
  })
}

但这并没有什么不同。

4

4 回答 4

2

您需要返回承诺ensureDir()以使其等待。

于 2019-05-21T20:56:41.677 回答
1

让我过度简化您的代码来说明问题:

p1.then(() => {
  p2.then().then().then()
}).then(/* ??? */)

这与以下内容相同:

p1.then(() => {
  p2.then().then().then()
  return undefined
}).then(/* undefined */)


您需要链接的是返回内部 Promise

p1.then(() => // no {code block} here, just return value
  p2.then().then().then()
).then(/* ??? */)

这与以下内容相同:

p1.then(() => {
  p3 = p2.then()
  p4 = p3.then()
  p5 = p4.then()
  return p5
}).then(/* p5 */)
于 2019-05-21T21:32:57.370 回答
1

我认为问题可能是您正在为每个.md文件创建一个读取流,但在尝试合并 outFiles 之前没有等待读取完成。

您可能会等到 outFiles 长度与md合并之前找到的文件数相同。

此外,您应该为此坚持使用 async/await。它将使代码更清晰

于 2019-05-21T21:01:11.153 回答
0

据我所知,最初的问题是方法,而不是其他人正确指出的明显错误。对于从多个 md 文件生成单个 pdf 的总体目标,我找到了一个更简单的解决方案。

const markdownpdf = require('markdown-pdf')
const path = require('path')
const fse = require('fs-extra')

const srcDir = '../manuscript'

const filterAndAddPath = (files) => {
  try {
    const mdFiles = files
      .filter(f => path.extname(f) === '.md')
      .map(f => `${srcDir}/${f}`)
    return mdFiles
  }
  catch (e) {
    console.log('filterAndAddPath', e)

  }
}

const main4 = async ()  => {
  const allFiles = await fse.readdir(srcDir)
  const mdFiles = filterAndAddPath(allFiles)
  const bookPath = 'book.pdf'
  markdownpdf()
    .concat.from(mdFiles)
    .to(bookPath, function() {
      console.log('Created', bookPath)
    })
}

main4()
于 2019-05-22T17:06:07.120 回答