调整一个不可链接到 return 值的函数
Adapting a function that isnt chainable to return a value
我正在尝试使用 pdfreader package 在一个对象中获取 pdf 的所有页面。该函数最初 return 在处理每个页面时(作为它自己的对象)。我的目标是编写一个 return 将所有页面作为页面对象数组的包装器。有人可以解释为什么这不起作用吗?
我试过了:
添加 .then 和 return 条件 - 因为我希望 parseFileItems 方法 return 一个值:
let pages = [];
new pdfreader.PdfReader()
.parseFileItems(pp, function(err, item) {
{
if (!item) {
return pages;
} 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);
}
}
})
.then(() => {
console.log("done" + pages.length);
});
得到错误
TypeError: Cannot read property 'then' of undefined
我正在修改的函数(来自包文档):
var pdfreader = require("pdfreader");
var rows = {}; // indexed by y-position
function printRows() {
Object.keys(rows) // => array of y-positions (type: float)
.sort((y1, y2) => parseFloat(y1) - parseFloat(y2)) // sort float positions
.forEach(y => console.log((rows[y] || []).join("")));
}
new pdfreader.PdfReader().parseFileItems("CV_ErhanYasar.pdf", function(
err,
item
) {
if (!item || item.page) {
// end of file, or page
printRows();
console.log("PAGE:", item.page);
rows = {}; // clear rows for next page
} else if (item.text) {
// accumulate text items into rows object, per line
(rows[item.y] = rows[item.y] || []).push(item.text);
}
});
如果你想链接一个 then
,你需要回调函数到 return 一个 Promise :
new pdfreader.PdfReader()
.parseFileItems(pp, function (err, item) {
return new Promise( (resolve, reject) => {
let pages = ...
// do stuff
resolve(pages);
}
})
.then( pages => {
console.log("done" + pages.length);
});
这里好像同时有好几个issues/misconceptions。让我们一次看一次。
首先,您似乎认为外部函数将 return ("pass on") 您的回调的 return 值
如您所见,情况并非如此in the library source。
此外,它甚至没有意义,因为回调为每个项目调用一次。因此,对于 10 个项目,它将被调用 10 次,那么 parseFileItems
怎么知道你的回调的 10 个 return 值中的哪一个传递给外部?
回调函数中的 return 并不重要,因为 parseFileItems
函数会忽略它。此外,parseFileItems
函数本身也没有 return 任何东西。因此,new pdfreader.parseFileItems(...)
的结果将始终评估为 undefined
(而 undefined
显然没有 属性 then
)。
其次,您似乎认为 .then
是某种通用的函数调用链接方法。
事实上,.then
是一种链接 承诺 或对承诺的实现做出反应的方法。在这种情况下,任何地方都没有承诺,特别是 parseFileItems
不是 return 承诺(它 return 是 undefined
如上所述),所以你不能调用.then
结果。
根据 the docs,您应该自己对错误和流结束做出反应。因此,您的代码将像这样工作:
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);
}
}
})
但是,我同意拥有一个 promise 包装器会更好,这样您就不必将以下所有代码都填充到回调的 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)
})
注意:使用 async generators 你会得到更好的代码,但现在在这里解释太多了,因为从回调到异步生成器的转换没有你想象的那么简单想想。
我正在尝试使用 pdfreader package 在一个对象中获取 pdf 的所有页面。该函数最初 return 在处理每个页面时(作为它自己的对象)。我的目标是编写一个 return 将所有页面作为页面对象数组的包装器。有人可以解释为什么这不起作用吗?
我试过了:
添加 .then 和 return 条件 - 因为我希望 parseFileItems 方法 return 一个值:
let pages = [];
new pdfreader.PdfReader()
.parseFileItems(pp, function(err, item) {
{
if (!item) {
return pages;
} 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);
}
}
})
.then(() => {
console.log("done" + pages.length);
});
得到错误
TypeError: Cannot read property 'then' of undefined
我正在修改的函数(来自包文档):
var pdfreader = require("pdfreader");
var rows = {}; // indexed by y-position
function printRows() {
Object.keys(rows) // => array of y-positions (type: float)
.sort((y1, y2) => parseFloat(y1) - parseFloat(y2)) // sort float positions
.forEach(y => console.log((rows[y] || []).join("")));
}
new pdfreader.PdfReader().parseFileItems("CV_ErhanYasar.pdf", function(
err,
item
) {
if (!item || item.page) {
// end of file, or page
printRows();
console.log("PAGE:", item.page);
rows = {}; // clear rows for next page
} else if (item.text) {
// accumulate text items into rows object, per line
(rows[item.y] = rows[item.y] || []).push(item.text);
}
});
如果你想链接一个 then
,你需要回调函数到 return 一个 Promise :
new pdfreader.PdfReader()
.parseFileItems(pp, function (err, item) {
return new Promise( (resolve, reject) => {
let pages = ...
// do stuff
resolve(pages);
}
})
.then( pages => {
console.log("done" + pages.length);
});
这里好像同时有好几个issues/misconceptions。让我们一次看一次。
首先,您似乎认为外部函数将 return ("pass on") 您的回调的 return 值
如您所见,情况并非如此in the library source。
此外,它甚至没有意义,因为回调为每个项目调用一次。因此,对于 10 个项目,它将被调用 10 次,那么 parseFileItems
怎么知道你的回调的 10 个 return 值中的哪一个传递给外部?
回调函数中的 return 并不重要,因为 parseFileItems
函数会忽略它。此外,parseFileItems
函数本身也没有 return 任何东西。因此,new pdfreader.parseFileItems(...)
的结果将始终评估为 undefined
(而 undefined
显然没有 属性 then
)。
其次,您似乎认为 .then
是某种通用的函数调用链接方法。
事实上,.then
是一种链接 承诺 或对承诺的实现做出反应的方法。在这种情况下,任何地方都没有承诺,特别是 parseFileItems
不是 return 承诺(它 return 是 undefined
如上所述),所以你不能调用.then
结果。
根据 the docs,您应该自己对错误和流结束做出反应。因此,您的代码将像这样工作:
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);
}
}
})
但是,我同意拥有一个 promise 包装器会更好,这样您就不必将以下所有代码都填充到回调的 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)
})
注意:使用 async generators 你会得到更好的代码,但现在在这里解释太多了,因为从回调到异步生成器的转换没有你想象的那么简单想想。