|
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