为了账号安全,请及时绑定邮箱和手机立即绑定

调整不可链接的函数以返回值

调整不可链接的函数以返回值

回首忆惘然 2022-05-26 17:18:52
我正在尝试使用pdfreader 包在一个对象中获取 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-positionfunction 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);  }});
查看完整描述

2 回答

?
凤凰求蛊

TA贡献1825条经验 获得超4个赞

这里似乎同时存在几个问题/误解。让我们试着一次看一次。


首先,您似乎认为外部函数将返回(“传递”)您的回调的返回值


正如您在库源代码中看到的那样,情况并非如此。


此外,它甚至没有意义,因为回调为每个项目调用一次。那么,对于 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);

      }

    }

  })

但是,我同意拥有一个 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)

})

注意:使用异步生成器你会得到更好的代码,但是现在在这里解释太多了,因为从回调到异步生成器的转换没有你想象的那么简单。


查看完整回答
反对 回复 2022-05-26
?
POPMUISE

TA贡献1765条经验 获得超5个赞

如果要链接 a 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);

    });


查看完整回答
反对 回复 2022-05-26
  • 2 回答
  • 0 关注
  • 102 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信