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环境:
- 修改导入语句:使用legacy路径导入pdf.js
typescript
import * as pdfjs from 'pdfjs-dist/legacy/build/pdf.min.mjs';
处理TypeScript类型声明: 在项目中创建
types.d.ts
文件(或在现有类型文件中)添加:typescriptdeclare module 'pdfjs-dist/legacy/build/pdf.min.mjs';
更新
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的浏览器构建版本,这会导致各种兼容性问题。始终确认使用的构建版本与环境匹配。