当前位置: 首页 > 知识库问答 >
问题:

javascript - html2canvas 性能优化方案有哪些?

宫晟
2024-03-06

项目中多处使用到 PDF 打印功能,我之前采用的实现方案是:

1 先在 html 上渲染出来
2 通过 html2canvas 转换为 canvas
3 通过 canvas.toDataURL 转换为 jpeg 图片 URL
4 通过 jspdf 创建 PDF 并添加转换来的 jpeg

PDF 模板中各元素尺寸是根据数据灵活变换的,考虑到纸张大小,换页,布局等问题,通过 html2canvas 将页面元素转换为 canvas 的时要根据实际情况进行多次转换生成包一个含多张图片的列表。jspdf 再根据图片列表逐一添加。

现在问题就来了,虽然功能已经实现,但 html2canvas 是异步操作,而且非常耗时,当页面只需要转换一两张图片的时候勉强还可以接受,但是当图片的数量越来越多,十张左右的时候就要二十多秒了。

为了优化这个问题,我查找并尝试了几种方法均已失败告终,方法和失败原因如下:

1 html2canvas 官网提供的 ignoreElements

根据介绍,ignoreElements 可以用来排除掉不需要被截图(转换为canvas)的 html 子元素,以便减少 html2canvas 遍历 HTML 元素的时间。但在我的项目中,因为前面提到的考虑换页等问题,已经对 html2canvas 转换的元素粒度降到最细了。没有可排除打印的子元素。

2 Promise.all 多个异步并行,

不知道是因为浏览器限制还是因为线程的资源上限,虽然在代码逻辑上多个 html2canvas 已经是并行处理了,但实际使用时间并没有减少,而且从F12的性能上看,多个 html2canvas 最终还是逐一执行的

3 web worker 后台线程处理

既然在同一个线程里没办法做到真正的并行处理,第一时间想到的就是 web worker 甚至可以使用多个 web worker 启用后台线程并行处理,但是 html2Canvas 是根据 DOM 元素进行操作处理,而 web worker 是没法访问 Dom 的,所以 html2Canvas 好像又不能放到后台线程中处理。

进行到这里就没了头绪,接下来该怎么做希望有遇到过这个问题的前辈给个方向,不胜感激。

共有2个答案

于正志
2024-03-06

我目前用的方案是将 PDF 文件嵌入到页面中,然后使用浏览器的打印功能来打印页面
代码大致如下:详细代码 demo

<iframe src="" id="iframe" frameborder="0"></iframe><script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script><script>  function loadpdf() {    axios({      method: 'get',      url:        './20200714144950101.pdf',      responseType: 'blob',    }).then(function (response) {      let blob = new Blob([response.data], { type: response.data.type })      let url = URL.createObjectURL(blob)      document.getElementById('iframe').src = url    })  }</script>

image.png


如果你的预览页面有样式要求,你可以用pdf.js去进行渲染和打印操作。
image.png
demo 源码直接右键网页源代码

丁良骏
2024-03-06

对于 html2canvas 的性能优化,这里有一些可能的方案和建议:

  1. 减少渲染的复杂性
* 如果可能,尝试简化页面元素的复杂性,例如减少动画、阴影、复杂的 CSS 样式等。这些元素可能会增加 `html2canvas` 的渲染时间。* 如果某些元素在打印版本中不需要,可以使用 CSS 媒体查询或 JavaScript 在转换前隐藏或删除它们。
  1. 使用 scale 选项
* `html2canvas` 允许你设置 `scale` 选项来降低渲染的分辨率。虽然这可能会降低图像的质量,但它可以显著提高渲染速度。* 例如:`html2canvas(element, { scale: 2 })` 会将渲染的分辨率降低到原来的一半。
  1. 批量处理
* 如果可能,尝试将多个页面元素组合到一个大的 `canvas` 上,然后一次性转换为图片,而不是为每个元素单独执行此操作。这可以减少转换的次数和开销。
  1. 使用 Web Workers 处理其他任务
* 虽然 `html2canvas` 无法在 Web Worker 中运行,但你可以使用 Web Workers 来处理其他与 DOM 无关的任务,从而释放主线程并使其专注于渲染。
  1. 使用其他库或方法
* 考虑使用其他库或方法,如 `dom-to-image` 或 `puppeteer`(基于 Chrome 的无头浏览器)来进行屏幕截图。这些库可能有不同的性能特性,并可能更适合你的用例。
  1. 服务器端渲染
* 如果可能,考虑将渲染过程移动到服务器端。这样,你可以利用更强大的硬件和更少的浏览器限制来执行渲染任务。你可以使用如 Node.js 和 Puppeteer 的组合来实现这一点。
  1. 性能分析和调优
* 使用浏览器的性能分析工具(如 Chrome 的开发者工具)来识别瓶颈和性能问题。这可能会帮助你找到可以优化的特定部分或操作。
  1. 异步加载和渲染
* 如果你的页面包含大量的动态内容或异步加载的资源,考虑在转换之前确保所有内容都已完全加载和渲染。这可以避免在转换过程中发生不必要的延迟或重绘。

请注意,具体的优化策略可能因你的特定用例和项目需求而有所不同。因此,建议从上述建议开始,并根据你的具体情况进行调整和测试。

 类似资料:
  • 本文向大家介绍react性能优化方案相关面试题,主要包含被问及react性能优化方案时的应答技巧和注意事项,需要的朋友参考一下 重写shouldComponentUpdate来避免不必要的dom操作0 使用 production 版本的react.js0 使用key来帮助React识别列表中所有子组件的最小变化。 参考链接: https://segmentfault.com/a/119000000

  • 本文向大家介绍vue性能的优化的方法有哪些?相关面试题,主要包含被问及vue性能的优化的方法有哪些?时的应答技巧和注意事项,需要的朋友参考一下 Vue 项目性能优化 — 实践指南

  • 本文向大家介绍Mysql性能优化方案分享,包括了Mysql性能优化方案分享的使用技巧和注意事项,需要的朋友参考一下 网上有不少mysql 性能优化方案,不过,mysql的优化同sql server相比,更为麻烦,同样的设置,在不同的环境下 ,由于内存,访问量,读写频率,数据差异等等情况,可能会出现不同的结果,因此简单地根据某个给出方案来配置mysql是行不通的,最好能使用status信息对mysq

  • 避免不必要的 DOM 操作 浏览器遍历 DOM 元素的代价是昂贵的。最简单优化 DOM 树查询的方案是,当一个元素出现多次时,将它保存在一个变量中,就避免多次查询 DOM 树了。 // Recommended var myList = ""; var myListHTML = document.getElementById("myList").innerHTML; for (var i

  • 本文向大家介绍针对jQuery性能的优化方法有哪些?相关面试题,主要包含被问及针对jQuery性能的优化方法有哪些?时的应答技巧和注意事项,需要的朋友参考一下 show slide animate 等频繁修改 dom 很耗性能,可采用 jquery.transit 插件等 使用单个 id 或 class 选择器当然也是优化点咯,元素选择器是真的会卡 每次调用 $() 其实都是生成一个超大的对象,还

  • 本文向大家介绍你知道的react性能优化有哪些方法?相关面试题,主要包含被问及你知道的react性能优化有哪些方法?时的应答技巧和注意事项,需要的朋友参考一下 :Class Component :Function Component :Memoized Function :Memozied Value