调整不可链接的函数以返回值
Posted
技术标签:
【中文标题】调整不可链接的函数以返回值【英文标题】:Adapting a function that isnt chainable to return a value 【发布时间】:2020-03-23 15:56:22 【问题描述】:我正在尝试使用pdfreader package 在一个对象中获取 pdf 的所有页面。该函数在处理它时最初返回每个页面(作为它自己的对象)。我的目标是编写一个将所有页面作为页面对象数组返回的包装器。有人可以解释为什么这不起作用吗?
我试过了:
添加 .then 和返回条件 - 因为我希望 parseFileItems 方法返回一个值:
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: 无法读取未定义的属性“then”
我正在修改的函数(来自包文档):
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);
);
【问题讨论】:
你似乎在期待parseFileItems()
回报一个承诺。它不返回任何东西,它只是调用回调函数。如果您希望它以这种方式工作,您需要创建自己的 Promise。
【参考方案1】:
这里似乎同时存在几个问题/误解。让我们试着一次看一次。
首先,您似乎认为外部函数将返回(“传递”)您的回调的返回值
如您所见in the library source,情况并非如此。
此外,它甚至没有意义,因为回调为每个项目调用一次。那么,有 10 个项目,它会被调用 10 次,那么parseFileItems
怎么知道你的回调的 10 个返回值中的哪一个要传递给外部呢?
从回调函数返回什么并不重要,因为parseFileItems
函数只是忽略它。此外,parseFileItems
函数本身也不返回任何内容。因此,new pdfreader.parseFileItems(...)
的结果将始终评估为undefined
(而undefined
显然没有属性then
)。
其次,您似乎认为.then
是一种用于函数调用的通用链接方法。
事实上,.then
是一种链接promises 的方式,或者对承诺的履行作出反应。在这种情况下,任何地方都没有任何承诺,特别是parseFileItems
不会返回承诺(它返回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 可以得到更好的代码,但现在在这里解释太多了,因为从回调到异步生成器的转换没有你想象的那么简单。
【讨论】:
您的第一个示例效果很好,但是当我使用承诺版本时,它永远不会返回任何内容 你能描述一下你的意思吗?是否输出done 0
?
哦,我忘了打电话给parseFileItems
,对不起!更新了我的答案【参考方案2】:
如果你想链接一个then
,你需要回调函数返回一个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);
);
【讨论】:
从回调中返回不一定会从parseFileItems
返回!正如您在library source 中看到的那样,它确实没有。以上是关于调整不可链接的函数以返回值的主要内容,如果未能解决你的问题,请参考以下文章
Firebase:snapshot.val 不是函数或其返回值不可迭代
20170313 ABAP以jason 格式返回值到http(接口内容返回)
Kotlin 协程Flow 异步流 ① ( 以异步返回返回多个返回值 | 同步调用返回多个值的弊端 | 尝试在 sequence 中调用挂起函数返回多个返回值 | 协程中调用挂起函数返回集合 )
Kotlin 协程Flow 异步流 ① ( 以异步返回返回多个返回值 | 同步调用返回多个值的弊端 | 尝试在 sequence 中调用挂起函数返回多个返回值 | 协程中调用挂起函数返回集合 )