|
30 | 30 | images: images,
|
31 | 31 | util: util,
|
32 | 32 | inliner: inliner,
|
| 33 | + urlCache: [], |
33 | 34 | options: {}
|
34 | 35 | }
|
35 | 36 | };
|
|
80 | 81 | options.width || util.width(node),
|
81 | 82 | options.height || util.height(node)
|
82 | 83 | );
|
83 |
| - }); |
| 84 | + }) |
| 85 | + .then(clearCache); |
| 86 | + |
| 87 | + function clearCache(result) { |
| 88 | + domtoimage.impl.urlCache = []; |
| 89 | + return result; |
| 90 | + } |
84 | 91 |
|
85 | 92 | function applyOptions(clone) {
|
86 | 93 | if (options.bgcolor) { clone.style.backgroundColor = options.bgcolor; }
|
|
568 | 575 | }
|
569 | 576 |
|
570 | 577 | 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 | + }); |
576 | 581 |
|
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 | + } |
580 | 589 |
|
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(); |
587 | 595 | }
|
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 | + } |
596 | 617 | }
|
597 |
| - } |
598 | 618 |
|
599 |
| - function done() { |
600 |
| - if (request.readyState !== 4) { return; } |
| 619 | + function done() { |
| 620 | + if (request.readyState !== 4) { return; } |
601 | 621 |
|
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() { |
603 | 641 | if (placeholder) {
|
604 | 642 | resolve(placeholder);
|
605 | 643 | } else {
|
606 |
| - fail(`cannot fetch resource: ${url}, status: ${request.status}`); |
| 644 | + fail(`timeout of ${httpTimeout}ms occured while fetching resource: ${url}`); |
607 | 645 | }
|
608 |
| - |
609 |
| - return; |
610 | 646 | }
|
611 | 647 |
|
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(''); |
625 | 651 | }
|
626 |
| - } |
627 |
| - |
628 |
| - function fail(message) { |
629 |
| - console.error(message); |
630 |
| - resolve(''); |
631 |
| - } |
632 |
| - }); |
| 652 | + }); |
| 653 | + } |
| 654 | + return cacheEntry.promise; |
633 | 655 | }
|
634 | 656 |
|
635 | 657 | function dataAsUrl(content, type) {
|
|
0 commit comments