fix: iframe load to ensure images are loaded (#2577)

This commit is contained in:
Niklas von Hertzen 2021-07-14 16:18:43 +08:00 committed by GitHub
parent 52a03c76b6
commit eeb5a3ea1d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -97,6 +97,10 @@ export class DocumentCloner {
await documentClone.fonts.ready; await documentClone.fonts.ready;
} }
if (/(AppleWebKit)/g.test(navigator.userAgent)) {
await imagesReady(documentClone);
}
if (typeof onclone === 'function') { if (typeof onclone === 'function') {
return Promise.resolve() return Promise.resolve()
.then(() => onclone(documentClone)) .then(() => onclone(documentClone))
@ -462,6 +466,25 @@ const createIFrameContainer = (ownerDocument: Document, bounds: Bounds): HTMLIFr
return cloneIframeContainer; return cloneIframeContainer;
}; };
const imageReady = (img: HTMLImageElement): Promise<Event | void | string> => {
return new Promise((resolve) => {
if (img.complete) {
resolve();
return;
}
if (!img.src) {
resolve();
return;
}
img.onload = resolve;
img.onerror = resolve;
});
};
const imagesReady = (document: HTMLDocument): Promise<unknown[]> => {
return Promise.all([].slice.call(document.images, 0).map(imageReady));
};
const iframeLoader = (iframe: HTMLIFrameElement): Promise<HTMLIFrameElement> => { const iframeLoader = (iframe: HTMLIFrameElement): Promise<HTMLIFrameElement> => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const cloneWindow = iframe.contentWindow; const cloneWindow = iframe.contentWindow;
@ -472,11 +495,8 @@ const iframeLoader = (iframe: HTMLIFrameElement): Promise<HTMLIFrameElement> =>
const documentClone = cloneWindow.document; const documentClone = cloneWindow.document;
cloneWindow.onload = cloneWindow.onload = iframe.onload = () => {
iframe.onload = cloneWindow.onload = iframe.onload = null;
documentClone.onreadystatechange =
() => {
cloneWindow.onload = iframe.onload = documentClone.onreadystatechange = null;
const interval = setInterval(() => { const interval = setInterval(() => {
if (documentClone.body.childNodes.length > 0 && documentClone.readyState === 'complete') { if (documentClone.body.childNodes.length > 0 && documentClone.readyState === 'complete') {
clearInterval(interval); clearInterval(interval);