使用react-pdf v7.3.3偶现Worker was terminated错误,求排查思路
react-pdf@7.3.3 偶发 "Worker was terminated" 错误排查方案
使用react-pdf v7.3.3渲染PDF时,页面加载阶段偶发以下错误:
unpkg.com/pdfjs-dist@3.6.172/build/pdf.worker.min.js:22 Uncaught (in promise) Error: Worker was terminated at ensureNotTerminated (unpkg.com/pdfjs-dist@3.6.172/build/pdf.worker.min.js:22:2053) at onFailure (unpkg.com/pdfjs-dist@3.6.172/build/pdf.worker.min.js:22:10071)
已确认pdf.worker.min.js与pdf.js版本匹配,且最小复现示例无法重现该问题,核心代码如下:
App组件
import React from 'react'; import Previewer from './previewer/Previewer'; const App: React.FC = () => { return ( <div> <Previewer pdfUrl={"https://arxiv.org/pdf/2304.09103.pdf"}></Previewer> </div> ); } export default App;
Previewer组件核心逻辑
import React, { useState } from 'react'; import { Document, Page, pdfjs } from 'react-pdf'; pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.js`; const Previewer: React.FC<{pdfUrl: string | undefined}> = (props) => { const [pdfScale, setPdfScale] = useState<number>(1); const [numPages, setNumPages] = useState<number>(); // 注意:此处cMapUrl使用了与pdfjs.version不一致的版本 const options = { cMapUrl: 'https://cdn.jsdelivr.net/npm/pdfjs-dist@3.9.179/cmaps/', }; const onDocumentLoadSuccess = (pdf: any) => { setNumPages(pdf.numPages); } // 一次性渲染所有PDF页面 const renderPages = (totalPageNum: number | undefined) => { if (!totalPageNum || totalPageNum < 1) return; const tagList: JSX.Element[] = []; for (let i = 1; i <= totalPageNum; i++) { tagList.push( <Page key={i} scale={pdfScale} pageNumber={i} ></Page> ); } return tagList; } return ( <div> <Document options={options} file={props.pdfUrl} onLoadSuccess={onDocumentLoadSuccess}> {renderPages(numPages)} </Document> </div> ); } export default Previewer;
可能的解决方向
1. 统一pdfjs相关资源版本
你的代码中cMapUrl使用的是pdfjs-dist@3.9.179,但react-pdf依赖的pdfjs-dist是3.6.172,版本不一致会导致内部逻辑冲突,修改为对应版本:
const options = { cMapUrl: `https://cdn.jsdelivr.net/npm/pdfjs-dist@${pdfjs.version}/cmaps/`, };
2. 避免批量渲染所有页面
一次性渲染所有Page组件会瞬间向worker发送大量渲染请求,超出浏览器worker资源限制导致被终止。改为分页渲染(仅渲染当前可见区域的页面):
const [pageNumber, setPageNumber] = useState<number>(1); // 只渲染当前页及前后1页 const renderPages = (totalPageNum: number | undefined) => { if (!totalPageNum || totalPageNum < 1) return; const tagList: JSX.Element[] = []; const startPage = Math.max(1, pageNumber - 1); const endPage = Math.min(totalPageNum, pageNumber + 1); for (let i = startPage; i <= endPage; i++) { tagList.push( <Page key={i} scale={pdfScale} pageNumber={i} ></Page> ); } return tagList; }
3. 改用本地worker资源
CDN加载worker可能因网络波动、缓存问题导致初始化不完整,将pdf.worker.min.js下载到项目静态资源目录,修改workerSrc指向本地路径:
pdfjs.GlobalWorkerOptions.workerSrc = '/static/pdf.worker.min.js';
4. 组件卸载时清理worker实例
组件在PDF加载过程中被卸载时,未完成的worker任务会抛出终止错误,添加卸载时的清理逻辑:
import { useRef, useEffect } from 'react'; const Previewer: React.FC<{pdfUrl: string | undefined}> = (props) => { const documentRef = useRef<any>(null); useEffect(() => { return () => { if (documentRef.current) { documentRef.current.destroy(); // 销毁worker实例 } }; }, []); // ...其他逻辑 return ( <div> <Document ref={documentRef} options={options} file={props.pdfUrl} onLoadSuccess={onDocumentLoadSuccess}> {renderPages(numPages)} </Document> </div> ); }
内容的提问来源于stack exchange,提问作者Dolphin
相关产品推荐
相关产品推荐

