Skip to content

Commit 2c54d7f

Browse files
committed
Added cache for all resource requests
This eliminates the constant redownloading of referenced fonts images and such. The cache is cleared after the completion of the toSvg method and is based on the requested URL, not the cache-busted URL. Based on the work in tsayen#336 and resolves #79
1 parent a14c03c commit 2c54d7f

File tree

1 file changed

+72
-50
lines changed

1 file changed

+72
-50
lines changed

src/dom-to-image-more.js

+72-50
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
images: images,
3131
util: util,
3232
inliner: inliner,
33+
urlCache: [],
3334
options: {}
3435
}
3536
};
@@ -80,7 +81,13 @@
8081
options.width || util.width(node),
8182
options.height || util.height(node)
8283
);
83-
});
84+
})
85+
.then(clearCache);
86+
87+
function clearCache(result) {
88+
domtoimage.impl.urlCache = [];
89+
return result;
90+
}
8491

8592
function applyOptions(clone) {
8693
if (options.bgcolor) { clone.style.backgroundColor = options.bgcolor; }
@@ -568,68 +575,83 @@
568575
}
569576

570577
function getAndEncode(url) {
571-
if (domtoimage.impl.options.cacheBust) {
572-
// Cache bypass so we dont have CORS issues with cached images
573-
// Source: https://developer.mozilla.org/en/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest#Bypassing_the_cache
574-
url += ((/\?/).test(url) ? "&" : "?") + (new Date()).getTime();
575-
}
578+
let cacheEntry = domtoimage.impl.urlCache.find(function (el) {
579+
return el.url === url;
580+
});
576581

577-
return new Promise(function (resolve) {
578-
const httpTimeout = domtoimage.impl.options.httpTimeout;
579-
const request = new XMLHttpRequest();
582+
if (!cacheEntry) {
583+
cacheEntry = {
584+
url: url,
585+
promise: null
586+
};
587+
domtoimage.impl.urlCache.push(cacheEntry);
588+
}
580589

581-
request.onreadystatechange = done;
582-
request.ontimeout = timeout;
583-
request.responseType = 'blob';
584-
request.timeout = httpTimeout;
585-
if (domtoimage.impl.options.useCredentials) {
586-
request.withCredentials = true;
590+
if (cacheEntry.promise === null) {
591+
if (domtoimage.impl.options.cacheBust) {
592+
// Cache bypass so we dont have CORS issues with cached images
593+
// Source: https://developer.mozilla.org/en/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest#Bypassing_the_cache
594+
url += ((/\?/).test(url) ? "&" : "?") + (new Date()).getTime();
587595
}
588-
request.open('GET', url, true);
589-
request.send();
590-
591-
let placeholder;
592-
if (domtoimage.impl.options.imagePlaceholder) {
593-
const split = domtoimage.impl.options.imagePlaceholder.split(/,/);
594-
if (split && split[1]) {
595-
placeholder = split[1];
596+
597+
cacheEntry.promise = new Promise(function (resolve) {
598+
const httpTimeout = domtoimage.impl.options.httpTimeout;
599+
const request = new XMLHttpRequest();
600+
601+
request.onreadystatechange = done;
602+
request.ontimeout = timeout;
603+
request.responseType = 'blob';
604+
request.timeout = httpTimeout;
605+
if (domtoimage.impl.options.useCredentials) {
606+
request.withCredentials = true;
607+
}
608+
request.open('GET', url, true);
609+
request.send();
610+
611+
let placeholder;
612+
if (domtoimage.impl.options.imagePlaceholder) {
613+
const split = domtoimage.impl.options.imagePlaceholder.split(/,/);
614+
if (split && split[1]) {
615+
placeholder = split[1];
616+
}
596617
}
597-
}
598618

599-
function done() {
600-
if (request.readyState !== 4) { return; }
619+
function done() {
620+
if (request.readyState !== 4) { return; }
601621

602-
if (request.status !== 200) {
622+
if (request.status !== 200) {
623+
if (placeholder) {
624+
resolve(placeholder);
625+
} else {
626+
fail(`cannot fetch resource: ${url}, status: ${request.status}`);
627+
}
628+
629+
return;
630+
}
631+
632+
const encoder = new FileReader();
633+
encoder.onloadend = function () {
634+
const content = encoder.result.split(/,/)[1];
635+
resolve(content);
636+
};
637+
encoder.readAsDataURL(request.response);
638+
}
639+
640+
function timeout() {
603641
if (placeholder) {
604642
resolve(placeholder);
605643
} else {
606-
fail(`cannot fetch resource: ${url}, status: ${request.status}`);
644+
fail(`timeout of ${httpTimeout}ms occured while fetching resource: ${url}`);
607645
}
608-
609-
return;
610646
}
611647

612-
const encoder = new FileReader();
613-
encoder.onloadend = function () {
614-
const content = encoder.result.split(/,/)[1];
615-
resolve(content);
616-
};
617-
encoder.readAsDataURL(request.response);
618-
}
619-
620-
function timeout() {
621-
if (placeholder) {
622-
resolve(placeholder);
623-
} else {
624-
fail(`timeout of ${httpTimeout}ms occured while fetching resource: ${url}`);
648+
function fail(message) {
649+
console.error(message);
650+
resolve('');
625651
}
626-
}
627-
628-
function fail(message) {
629-
console.error(message);
630-
resolve('');
631-
}
632-
});
652+
});
653+
}
654+
return cacheEntry.promise;
633655
}
634656

635657
function dataAsUrl(content, type) {

0 commit comments

Comments
 (0)