【问题标题】:async function re-entering without being called异步函数重新进入而不被调用
【发布时间】:2022-01-17 05:25:53
【问题描述】:

这很可能是由于我对 JavaScript 的经验有限,但我无法弄清楚这一点。这是一个Vue 2 + Typescript的项目,但具体问题与Vue或Typescript无关。

好的。所以我在我的一个组件中添加了以下功能。该组件的主要目的是获取 PDF 文件并以Blob 的形式返回其第一页的光栅化版本。这是我的功能:

async importButtonHandler () {
  if (this.file) {
    const blob = await this.pdfToBlob(this.file)
    if (blob) {
      const file2 = new File([blob], 'raster_pdf', { type: 'image/png' })
      // Further processing
    }
  }
}

async pdfToBlob (pdfFile: File): Promise<Blob|null> {
  const canvas: HTMLCanvasElement = document.createElement('canvas')
  const buffer = await this.readFileAsync(pdfFile)
  const typedarray = new Uint8Array(buffer)

  // get handle of pdf document
  const doc = await pdfjsLib.getDocument(typedarray).promise

  // get handle of page
  const pdfpage = await doc.getPage(1)

  // get viewport to render the page at required scale
  const viewport = pdfpage.getViewport()

  // set canvas height same as viewport height
  canvas.height = viewport.height
  canvas.width = viewport.width

  const renderContext: RenderParameters = {
    canvasContext: canvas.getContext('2d') as CanvasRenderingContext2D,
    viewport: viewport
  }

  // render the page contents in the canvas
  await pdfpage.render(renderContext).promise

  return new Promise((resolve, reject) => {
    try {
      canvas.toBlob(resolve)
    } catch (error) {
      reject(error)
    }
  })
}

readFileAsync (file: File): Promise<ArrayBuffer> {
  return new Promise((resolve, reject) => {
    const reader = new FileReader()

    reader.onload = () => {
      resolve(reader.result as ArrayBuffer)
    }

    reader.onerror = reject

    reader.readAsArrayBuffer(file)
  })
}

它点击函数pdfToBlob并从其中调用readFileAsync,正确地将文件读入buffer,但之后立即(在const typedarray = new Uint8Array(buffer)上)而不是执行该行,它再次点击pdfToBlob函数然后抛出一个异常说:

TypeError: Cannot read properties of undefined (reading 'getDocument')

对于我的生活,我无法弄清楚为什么它再次进入函数(没有其他地方调用此函数)。

我的直觉是我在函数中返回的 Promise,但我所有的实验都没有让我找到任何线索。

谁能帮我弄清楚这里出了什么问题?

【问题讨论】:

  • 你怎么打电话给importButtonHandler()。在我看来,您可能会多次调用该函数而无需等待先前的调用完成。
  • 此外,您得到的特定错误使pdfjsLib 看起来像undefined。这个变量是从哪里来的?
  • @jfriend00:我只是想通了。但我看不出我是如何调用它两次的。字符串importButtonHandler 在整个源代码中只出现了两次。一个是函数签名本身,另一个是我的前端按钮的点击事件绑定&lt;v-btn @click="importButtonHandler" /&gt;
  • @jfriend00: pdfjsLib 只是以下导入:import pdfjsLib from 'pdfjs-dist'
  • 我不知道&lt;v-btn @click="importButtonHandler" /&gt; 是什么。也许您可以显示浏览器看到的实际生成的 HTML/Javascript。

标签: javascript async-await promise pdf.js


【解决方案1】:

想通了(有点)。

首先,在调用getDocument 之前,我的pdfjsLib 需要正确导入并提供一个worker。这是我第二个问题的原因。下面是在 Vue 2/Typescript 项目中导入 lib 和 worker 的正确方法:

import * as pdfjsLib from 'pdfjs-dist'
import pdfjsWorker from 'pdfjs-dist/build/pdf.worker.entry'

然后将worker提供给图书馆并调用getDocument:

pdfjsLib.GlobalWorkerOptions.workerSrc = pdfjsWorker
const doc = await pdfjsLib.getDocument(YOUR_PDF_DATA).promise

我的 OP 中的其余代码可以正常工作。请注意,pdf.worker.entry 没有类型定义(或者至少我无法在任何地方找到它们),但它仍然有效。

多次调用处理程序的第一个问题似乎是 Vuetify 中的一个已知问题(或行为,如果您愿意)。他们建议在定义click 属性(如@click.stop="importButtonHandler")时使用nativepreventstop 来缓解这种行为。我试过没有成功。我的处理程序仍然被调用两次。在我的特定情况下,这不会造成任何功能损害,所以我现在可以忍受它,但我可以想到这种行为可能是灾难性的情况。

希望这对以后的人有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-10-19
    • 1970-01-01
    • 2020-01-26
    • 2010-12-08
    • 1970-01-01
    • 2020-01-17
    • 2021-11-07
    • 1970-01-01
    相关资源
    最近更新 更多