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

使用PDF.js在IE浏览器展示PDF页面顺序错乱如何修复?

修复IE浏览器中PDF.js加载大体积PDF时页面顺序错乱的问题

嘿,这个问题我之前帮人排查过,核心是异步操作的执行顺序不可控——尤其是在IE这种对异步处理比较“固执”的浏览器里,大体积PDF不同页面的加载耗时差异会把这个问题彻底放大。

为什么你的代码会出问题?

你代码里的pdf.getPage()是异步方法,返回的是Promise。在for循环里直接调用它时,循环会飞快地跑完所有pageNum,但每个getPage的回调要等页面加载完成才会执行。大PDF的页面大小、复杂度不一样,加载速度有快有慢,哪个先加载完就先渲染到页面上,自然就打乱了原本的顺序。IE的事件循环机制和现代浏览器有差异,这就导致这个问题在大PDF上表现得特别明显。

靠谱的修复方案

我们需要强制页面按顺序渲染,这里有两种兼容IE的可行方法:

方法1:用Promise链式调用(原生兼容IE)

因为IE不支持async/await,所以用Promise链式调用是最稳妥的原生方案:

if (response && response.data.Success) {
  var arrayBufferedPdf = base64ToArrayBuffer(response.data.Document);
  PDFJS.workerSrc = "./scripts/pdf.worker.js";
  
  PDFJS.getDocument({ data: arrayBufferedPdf }).then(function (pdf) {
    var numPages = pdf.numPages;
    // 初始化一个已完成的Promise,用来串联所有渲染步骤
    let renderSequence = Promise.resolve();
    
    for (let pageNum = 1; pageNum <= numPages; pageNum++) {
      // 用立即执行函数保存当前循环的pageNum,避免异步回调拿错值
      (function(currentPage) {
        renderSequence = renderSequence.then(function() {
          return pdf.getPage(currentPage).then(function(page) {
            var scale = 1.25;
            var viewport = page.getViewport(scale);
            var canvasContainer = document.getElementById('canvas_container');
            var canvas = document.createElement('canvas');
            canvas.height = viewport.height;
            canvas.width = viewport.width;
            canvasContainer.appendChild(canvas);
            var context = canvas.getContext('2d');
            // 等待当前页面渲染完成,再进入下一个步骤
            return page.render({ canvasContext: context, viewport: viewport }).promise;
          });
        });
      })(pageNum);
    }
  });
}

关键改动点:

  • 用renderSequence这个Promise来串联所有页面的渲染,确保上一页渲染完成后才开始下一页
  • 用立即执行函数(IIFE)把当前循环的pageNum保存到独立作用域,避免异步回调时引用到循环结束后的变量值
  • 等待page.render()的promise完成,确保页面真的渲染完了再继续

方法2:用async/await(需转译兼容IE)

如果你的项目有用Babel这类转译工具,可以用更简洁的async/await写法,逻辑一目了然:

if (response && response.data.Success) {
  var arrayBufferedPdf = base64ToArrayBuffer(response.data.Document);
  PDFJS.workerSrc = "./scripts/pdf.worker.js";
  
  PDFJS.getDocument({ data: arrayBufferedPdf }).then(async function (pdf) {
    var numPages = pdf.numPages;
    var canvasContainer = document.getElementById('canvas_container');
    
    for (let pageNum = 1; pageNum <= numPages; pageNum++) {
      // 等待当前页面加载完成
      const page = await pdf.getPage(pageNum);
      var scale = 1.25;
      var viewport = page.getViewport(scale);
      var canvas = document.createElement('canvas');
      canvas.height = viewport.height;
      canvas.width = viewport.width;
      canvasContainer.appendChild(canvas);
      var context = canvas.getContext('2d');
      // 等待当前页面渲染完成,再进入下一次循环
      await page.render({ canvasContext: context, viewport: viewport }).promise;
    }
  });
}

关键改动点:

  • 给PDF文档加载完成的回调标记async,在循环里用await强制等待异步操作完成
  • 用let声明pageNum,确保每次循环都有独立的作用域,不会出现变量污染

额外小贴士

  • 尽量用较新的PDF.js版本,旧版本在IE下的兼容性问题更多
  • 大体积PDF全量渲染可能会吃很多内存,IE的内存限制比较严格,要是用户体验还不好,可以考虑做按需渲染——只渲染当前可见区域的页面,能大幅提升性能

内容的提问来源于stack exchange,提问作者Jack philip

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 06:30:42