第一步不能在 Web-Worker 中完成。您需要访问 DOM 才能绘制它,而 Workers 无权访问 DOM。
第二步可以在OffscreenCanvas上完成,html2canvas确实接受{ canvas }参数,您也可以将其设置为OffscreenCanvas。
但是,一旦您从 OffscreenCanvas 获得上下文,您就无法再将其传输,因此您将无法将该 OffscreenCanvas 传递给 Worker,并且您不会从中获利,因为一切仍将在 UI 线程上完成。
所以我们能做的最好的就是让html2canvas 初始化一个HTMLCanvasElement,在它上面绘图,然后将它转换成一个Blob 中的图像。 Blob 可以在没有任何复制成本的情况下遍历领域,并且 toBlob() 方法可以使其压缩部分异步完成。
第三步可以在一个Worker中完成,因为this PR。
我不知道 react 所以你必须重写它,但这里是一个裸 JS 实现:
script.js
const dpr = window.devicePixelRatio;
const worker = new Worker( "worker.js" );
worker.onmessage = makeDownloadLink;
worker.onerror = console.error;
html2canvas( target ).then( canvas => {
canvas.toBlob( (blob) => worker.postMessage( {
source: blob,
width: canvas.width / dpr, // retina?
height: canvas.height / dpr // retina?
} ) );
} );
worker.js
importScripts( "https://unpkg.com/jspdf@latest/dist/jspdf.umd.min.js" );
onmessage = ({ data }) => {
const { source, width, height } = data;
const reader = new FileReaderSync();
const data_url = reader.readAsDataURL( source );
const doc = new jspdf.jsPDF( { unit: "px", format: [ width, height ], orientation: width > height ? "l" : "p" });
doc.addImage( data_url, "PNG", 0, 0, width, height, { compression: "NONE" } );
postMessage( doc.output( "blob" ) );
};
而且由于 StackSnippet 的过度保护 iframe 确实会破坏 html2canvas,因此这里是 outsourced live example。