You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在自定义类中使用pdf.js的promise?this指向undefined报错如何解决

错误原因

你遇到的TypeError: this is undefined错误本质是普通函数的this指向丢失,出在PdfLoader类的getPageAsCanvas方法的Promise回调逻辑中:

  • 你使用function(){}定义Promise回调函数时,函数内部的this不会绑定到PdfLoader实例,类内部默认开启严格模式,此时this指向为undefined
  • 错误具体触发点是最内层的renderTask.promise.then(function(){ this.customPdfViewer.insertPageToBuffer(...) }),this找不到抛出异常后被外层的catch捕获,所以看起来单次调用中then和catch会先后执行,实际是内层then抛出异常触发了外层catch。

另外还存在一个隐性问题:每次调用getPageAsCanvas都会重新执行pdfjsLib.getDocument加载一次PDF,重复加载会浪费性能。


修复方案

两种方案任选其一即可解决问题:

方案1:将所有普通回调函数替换为箭头函数

箭头函数不会创建独立的this上下文,会继承外层作用域的this指向,直接替换所有function(){}格式的回调即可。
修改后的getPageAsCanvas代码如下:

getPageAsCanvas(pageNum){
    // 新增PDF实例缓存逻辑,避免重复加载
    if(this.pdfDocument) {
        this.renderPage(pageNum, this.pdfDocument);
        return;
    }
    this.loadingTask = pdfjsLib.getDocument(this.pdfPath);
    this.loadingTask.promise
        .then((pdfDocument) => {
            // 缓存PDF实例
            this.pdfDocument = pdfDocument;
            if(pdfDocument.numPages >= pageNum){
                return pdfDocument.getPage(pageNum).then((pdfPage) => {
                    const viewport = pdfPage.getViewport({ scale: 1.0 });
                    const canvas = document.getElementById("pdfCanvas");
                    canvas.width = viewport.width;
                    canvas.height = viewport.height;
                    const ctx = canvas.getContext("2d");
                    const renderTask = pdfPage.render({
                        canvasContext: ctx,
                        viewport,
                    });
                    return renderTask.promise.then(() => {
                        this.customPdfViewer.insertPageToBuffer(pageNum, canvas);
                    })
                })
            }
            console.log('Page ' + pageNum + ' 不存在!');
        })
        .catch(function (reason) {
            console.error("Error: " + reason);
        });
}

方案2:提前缓存this指向

如果不想使用箭头函数,可以在方法开头把PdfLoader实例的this存到临时变量中,回调里直接使用该变量访问实例:

getPageAsCanvas(pageNum){
    const _this = this; // 提前缓存实例this
    this.loadingTask = pdfjsLib.getDocument(this.pdfPath);
    this.loadingTask.promise
        .then(function (pdfDocument) {
            if(pdfDocument.numPages >= pageNum){
                return pdfDocument.getPage(pageNum).then(function (pdfPage) {
                    const viewport = pdfPage.getViewport({ scale: 1.0 });
                    const canvas = document.getElementById("pdfCanvas");
                    canvas.width = viewport.width;
                    canvas.height = viewport.height;
                    const ctx = canvas.getContext("2d");
                    const renderTask = pdfPage.render({
                        canvasContext: ctx,
                        viewport,
                    });
                    return renderTask.promise.then(function(){
                        _this.customPdfViewer.insertPageToBuffer(pageNum, canvas);
                    })
                })
            }
            console.log('Page ' + pageNum + ' 不存在!');
        })
        .catch(function (reason) {
            console.error("Error: " + reason);
        });
}

额外优化建议
  • 复用PDF实例:将加载完成的pdfDocument缓存到PdfLoader实例上,后续加载页面时直接调用缓存实例的getPage方法,无需重复请求PDF文件
  • 画布清空:如果复用单个canvas渲染多页,渲染前要手动清空画布,避免上一页内容残留
  • 并发控制:多页批量加载时可以设置并发上限,避免同时渲染太多页面导致页面卡顿

内容的提问来源于stack exchange,提问作者Patrik Tschersich

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 08:30:01