.then () не ожидает предыдущего .then () - PullRequest
1 голос
/ 21 мая 2019

Я создаю процесс, который преобразует несколько файлов уценки в один PDF-файл. Он создает файл PDF для каждого файла .md, найденного в исходном каталоге. Затем он объединяет отдельные файлы 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 () и что нужно изменить, чтобы это не так.

Я также написал асинхронную / ожидающую версию, которая имела ту же проблему и работала с setTimeOut ()

Редактировать

В ответ на предложение Зака ​​Холта, вот асинхронная / ожидающая версия:

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 ]

2 голосов
/ 21 мая 2019

Вам нужно вернуть обещание от ensureDir(), чтобы оно его дождалось.

1 голос
/ 22 мая 2019

Позвольте мне упростить ваш код, чтобы проиллюстрировать проблему:

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

, что совпадает с:

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


Для цепочки вам нужно вернуть внутреннее обещание :
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 */)
1 голос
/ 22 мая 2019

Я думаю, что проблема может заключаться в том, что вы создаете поток чтения для каждого из файлов .md, но не ожидаете окончания чтения, прежде чем пытаться объединить outFiles.

Вы можете подождать, пока длина outFiles не станет равной количеству md файлов, найденных перед объединением.

Кроме того, вы должны придерживаться async / await для этого. Это сделает код намного яснее

0 голосов
/ 22 мая 2019

Насколько я могу судить, исходной проблемой был подход, а не очевидные ошибки, правильно указанные другими. Я нашел гораздо более простое решение для общей цели создания одного pdf-файла из нескольких md-файлов.

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