MouhibKhammassi opened a new issue, #38926:
URL: https://github.com/apache/superset/issues/38926

   ### Bug description
   
   Every time I click Download as image on a chart, the entire Superset UI 
locks up for roughly 6 seconds (longer on complex charts like large tables or 
Deck.gl maps). The page becomes completely unresponsive during this time, I 
cannot interact with anything. Once the freeze passes, the image downloads 
normally.
   The freeze is also synchronous. the browser does not show a spinner or 
loading state. The tab simply stops responding entirely mid-click, which is a 
distinct and more jarring experience than a normal async load.
   
   What makes this feel like a bug rather than expected behaviour is that the 
freeze is exactly the same duration every single time I download the same 
chart. Whether it is my first download or my tenth, the UI hangs for the same 
amount of time. It never gets faster. On most web applications, repeated 
operations on the same data get faster because the browser or application 
caches the work it has already done. That is not happening here.
   
   Steps to Reproduce:
   1-Open any dashboard containing a chart with moderate/high visual 
complexity. a table chart with 50+ rows, a pivot table, or a bar/line chart 
with a legend and axis labels all reproduce this reliably. Simpler charts (e.g. 
a big number tile with a single value) may only produce a short freeze.
   2-download the chart as an image
   3-the entire browser tab freezes for 6 seconds. No spinner or loading 
indicator , the page is just completely unresponsive. Then the .jpg file 
downloads.
   4-Without refreshing the page, click Download as image on the same chart 
again immediately.
   5- the tab freezes for exactly the same duration as the first time. The 
second download is no faster than the first.
   6-repeat n amount of times steps 2-4,The freeze duration is consistent on 
every single attempt, it never decreases.
   
   expected behavior:
   Subsequent downloads of the same chart in the same session should be 
significantly faster (ideally under 200ms) because the style information has 
already been calculated and should be reused. Most of the expensive/complex 
work is already done.
   
   The UI should not completely freeze during the download. or at minimum, the 
freeze should be short enough to be imperceptible on repeated downloads.
   
   ------
   This is not a slow network request. The freeze happens before any file is 
sent to the browser. it is the browser itself constructing the image from the 
live DOM. The download dialog appears only after the freeze ends, confirming 
the freeze is the image generation, not the file transfer.
   
   The code that processes styles is supposed to remember the style 
measurements it has already taken for each DOM element, so it does not have to 
re-measure them on the next download. This caching mechanism is present in the 
code. it is just being cleared at the end of every download, meaning the next 
download starts from scratch with no memory of the previous one. The cache 
fills up, the image is generated, and then the cache is immediately thrown away 
before it can ever benefit a second download.
   
   ------
   Proposed Fix:
   
   I traced through superset-frontend/src/utils/downloadAsImage.tsx to find 
where the cache is being cleared. The file is around 323 lines and the issue is 
a single line (256) inside the createEnhancedClone function's cleanup callback:
   
   const cleanup = () => {
     styleCache.delete?.(originalElement);   // ← this line is the problem
     if (tempContainer.parentElement) {
       tempContainer.parentElement.removeChild(tempContainer);
     }
   };
   
   styleCache is a WeakMap declared at module scope on line 85. It is meant to 
persist across downloads for the lifetime of the page. that is the whole point 
of it being module-scoped rather than created fresh inside each download call. 
Calling ".delete()" on it here wipes out the entry for originalElement 
immediately after every download completes, so the next download finds an empty 
cache and has to redo all the getComputedStyle work from scratch.
   
   The fix is to remove that one line. as Weakmap is designed to release its 
entries automatically once the DOM element they are keyed on is 
garbage-collected by the browser. Removing entries by hand while the element is 
still live and mounted in the DOM defeats the cache with no benefit.
   
   The cleanup function still needs to remove the temporary off-screen 
container it created (the tempContainer lines below), so those stay. Only the 
styleCache.delete line is removed:
   
   const cleanup = () => {
     if (tempContainer.parentElement) {
       tempContainer.parentElement.removeChild(tempContainer);
     }
   };
   
   
   
   
   
   
   
   ### Screenshots/recordings
   
   _No response_
   
   ### Superset version
   
   master / latest-dev
   
   ### Python version
   
   3.9
   
   ### Node version
   
   16
   
   ### Browser
   
   Chrome
   
   ### Additional context
   
   _No response_
   
   ### Checklist
   
   - [x] I have searched Superset docs and Slack and didn't find a solution to 
my problem.
   - [x] I have searched the GitHub issue tracker and didn't find a similar bug 
report.
   - [ ] I have checked Superset's logs for errors and if I found a relevant 
Python stacktrace, I included it here as text in the "additional context" 
section.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to