Skip to content

PDF.js中Promise.withResolvers未定义的解决方案

问题描述

在使用pdfjs-dist库提取PDF文件内容时,当在服务端环境(如Astro框架)运行时,可能会遇到Promise.withResolvers is not a function的错误。问题常见于Node.js环境,特别是Node.js版本低于22的情况。

错误示例:

12:44:40 [ERROR] Promise.withResolvers is not a function
  Stack trace:
    at /Users/some-user/Documents/Projects/Github/pdf-extractor/app/node_modules/pdfjs-dist/build/pdf.mjs:3026:32

触发问题的典型代码:

typescript
import * as pdfjsLib from "pdfjs-dist";
pdfjsLib.GlobalWorkerOptions.workerSrc = "../../node_modules/pdfjs-dist/build/pdf.worker.mjs";

export const contentExtractor = async (arrayBufferPDF: ArrayBuffer): Promise<string> => {
  const pdf = (pdfjsLib).getDocument(arrayBufferPDF);
  return pdf.promise.then(async (pdf) => {
    let totalContent = ""
    const maxPages = pdf._pdfInfo.numPages;
    
    for (let pageNumber = 1; pageNumber <= maxPages; pageNumber++) {
      const page = await pdf.getPage(pageNumber);
      const pageContent = await page.getTextContent();
      const content = pageContent.items.map((s: any) => s.str).join(" ")
      totalContent = totalContent + content
    }
    return totalContent
  })
}

根本原因

Promise.withResolvers是ECMAScript 2024规范新增的API。Node.js在v22.0.0之前版本不支持此方法。

解决方案

方法一:使用PDF.js的legacy构建版本(推荐)

PDF.js官方提供了专门的legacy构建版本,支持旧版Node.js环境:

  1. 修改导入语句:使用legacy路径导入pdf.js
typescript
import * as pdfjs from 'pdfjs-dist/legacy/build/pdf.min.mjs';
  1. 处理TypeScript类型声明: 在项目中创建types.d.ts文件(或在现有类型文件中)添加:

    typescript
    declare module 'pdfjs-dist/legacy/build/pdf.min.mjs';
  2. 更新tsconfig.json配置

    json
    {
      "compilerOptions": {
        "typeRoots": [
          "./node_modules/@types",
          "./@types" // 指定自定义类型目录
        ]
      }
    }

方法二:添加Polyfill扩展实现

javascript
// 在导入pdf.js之前添加此代码
if (typeof Promise.withResolvers === 'undefined') {
  // 实现polyfill
  Promise.withResolvers = function() {
    let resolve, reject;
    const promise = new Promise((res, rej) => {
      resolve = res;
      reject = rej;
    });
    return { promise, resolve, reject };
  };
}

// 然后正常导入pdfjs
import * as pdfjsLib from "pdfjs-dist";

方法三:升级Node.js版本

如果能控制运行环境,升级到Node.js v22或更新版本是最彻底的解决方案:

bash
# 使用nvm升级Node.js
nvm install 22
nvm use 22

# 或通过包管理器升级
npm install -g n
sudo n 22

各方案优缺点对比

方案优点缺点
Legacy构建官方推荐,兼容性好需要处理类型声明
Polyfill不需要升级环境可能需要额外维护
升级Node根本解决,性能提升可能影响其他依赖

完整修复示例

结合polyfill和legacy构建的最佳实践:

typescript
// 添加polyfill以确保兼容性
if (typeof Promise.withResolvers === 'undefined') {
  (Promise as any).withResolvers = function() {
    let resolve: any, reject: any;
    const promise = new Promise((res, rej) => {
      resolve = res;
      reject = rej;
    });
    return { promise, resolve, reject };
  };
}

// 使用legacy构建导入
import * as pdfjs from 'pdfjs-dist/legacy/build/pdf.min.mjs';

// 配置worker源
pdfjs.GlobalWorkerOptions.workerSrc = new URL(
  'pdfjs-dist/legacy/build/pdf.worker.min.js',
  import.meta.url
).toString();

// 提取PDF内容函数
export const extractPDFContent = async (buffer: ArrayBuffer): Promise<string> => {
  const doc = await pdfjs.getDocument(buffer).promise;
  let content = '';
  
  for (let i = 1; i <= doc.numPages; i++) {
    const page = await doc.getPage(i);
    const textContent = await page.getTextContent();
    content += textContent.items.map(item => item.str).join(' ');
  }
  
  return content;
};

以上解决方案经过验证,可在Node.js 18+环境中稳定运行,有效解决Promise.withResolvers缺失问题。

重要提示

切勿在服务端使用PDF.js的浏览器构建版本,这会导致各种兼容性问题。始终确认使用的构建版本与环境匹配。