Кажется, здесь есть несколько проблем / заблуждений одновременно. Давайте попробуем взглянуть на них по одному за раз.
Во-первых, вы, кажется, думали, что внешняя функция возвратит ("передаст") возвращаемое значение вашего обратного вызова
Это не case, как вы можете видеть в исходном коде библиотеки .
Кроме того, это даже не имеет смысла, потому что обратный вызов вызывается один раз для каждого элемента. Итак, с 10 элементами он будет вызван 10 раз, и тогда как parseFileItems
узнает, какое из 10 возвращаемых значений вашего обратного вызова передается наружу?
Не имеет значения, что вы возвращаете из функции обратного вызова, так как функция parseFileItems
просто игнорирует ее. Более того, сама функция parseFileItems
тоже ничего не возвращает. Таким образом, результат new pdfreader.parseFileItems(...)
всегда будет иметь значение undefined
(а undefined
, очевидно, не имеет свойства then
).
Во-вторых, вы, похоже, подумали, что .then
- это своего рода универсальный метод связывания для вызовов функций.
На самом деле, .then
- это способ связать обещания , или отреагировать на выполнение обещания. В этом случае нигде нет обещаний, и, в частности, parseFileItems
не возвращает обещание (оно возвращает undefined
, как описано выше), поэтому вы не можете вызвать .then
для его результата.
Согласно документам , вы должны реагировать на ошибки и конец потока самостоятельно. Итак, ваш код будет работать так:
let pages = [];
new pdfreader.PdfReader()
.parseFileItems(pp, function(err, item) {
{
if (!item) {
// ****** Here we are done! ******
console.log("done" + pages.length) // The code that was in the `then` goes here instead
} else if (item.page) {
pages.push(lines);
rows = {};
} else if (item && item.text) {
// accumulate text items into rows object, per line
(rows[item.y] = rows[item.y] || []).push(item.text);
}
}
})
Однако я согласен, что было бы лучше иметь упаковщик обещаний, чтобы вам не пришлось вставлять весь следующий код в колбэк if (!item)
филиал. Вы можете добиться этого, используя new Promise
:
const promisifiedParseFileItems = (pp, itemHandler) => new Promise((resolve, reject) => {
new pdfreader.PdfReader().parseFileItems(pp, (err, item) => {
if (err) {
reject(err)
} else if (!item) {
resolve()
} else {
itemHandler(item)
}
})
})
let pages = []
promisifiedParseFileItems(pp, item => {
if (item.page) {
pages.push(lines)
rows = {}
} else if (item && item.text) {
// accumulate text items into rows object, per line
(rows[item.y] = rows[item.y] || []).push(item.text)
}
}).then(() => {
console.log("done", pages.length)
}, e => {
console.error("error", e)
})
Примечание: вы получите еще более приятный код с асин c генераторами но это слишком много, чтобы объяснить здесь сейчас, потому что преобразование из обратного вызова в асинхронный генератор c менее тривиально, чем вы думаете.