Repository navigation
Opening an image in a directory with many files is very slow #3015
Description
Describe the bug
When opening an image in a directory with many (~10k) images, my browser hangs for about a minute. The longest time seems to be consumed by
Lines 797 to 799 in c77de03
| this.fileList = sortedNodes.map(node => { | |
| return filteredFiles.find(file => file.filename === node.path) | |
| }) |
The map() call here has a runtime complexity of O(n^2) with n being the number of files in the directory which is not ideal.
If I don't overlook something, the goal of
Lines 778 to 799 in c77de03
| // sort like the files list | |
| // TODO: implement global sorting API | |
| // https://github.com/nextcloud/server/blob/a83b79c5f8ab20ed9b4d751167417a65fa3c42b8/apps/files/lib/Controller/ApiController.php#L247 | |
| const nodes = filteredFiles.map( | |
| file => new NcFile({ | |
| source: davRemoteURL + davGetRootPath() + file.filename, | |
| id: file.fileid, | |
| displayname: file.displayname, | |
| mime: file.mime, | |
| mtime: new Date(file.lastmod), | |
| owner: this.currentFile.ownerId, | |
| root: davGetRootPath(), | |
| }), | |
| ) | |
| const sortedNodes = sortNodes(nodes, { | |
| sortingMode: this.sortingConfig.key, | |
| sortingOrder: this.sortingConfig.asc ? 'asc' : 'desc', | |
| }) | |
| this.fileList = sortedNodes.map(node => { | |
| return filteredFiles.find(file => file.filename === node.path) | |
| }) |
is to get
filteredFiles sorted and assign that to this.fileList.
From an algorithmic point of view, it should be possible that sortNodes() (or a similar function) returns a list of indices that sort the underlying list (here nodes) like argsort in NumPy. Then this list of indices can be used to reorder filteredFiles. Then, except for the sorting everything should run in O(n).
To Reproduce
Steps to reproduce the behavior:
- Open an image in a directory with many (~10k) images
- Wait until the prev/next buttons appear
Desktop (please complete the following information):
- OS: Ubuntu 22.04
- Browser Firefox 144.0.2
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsDone
Activity
skjnldsv commentedon Nov 26, 2025
Should be fixed once we have #2989
kokutoukiritsugu commentedon May 27, 2026
viewer 6.0.0 temp fix:
check the mjs file:
# grep -o -E '[a-zA-Z0-9_$]+\.fileList=\(\(\)=>[^)]+\)' apps/viewer/js/viewer-main.mjsthis.fileList=(()=>{const m=new Map(L.map(P=>[P.filename,P])replace use sed:
# sed -i 's/this\.fileList=D\.map(h=>L\.find(P=>P\.filename===h\.path))/this.fileList=(()=>{const m=new Map(L.map(P=>[P.filename,P]));return D.map(h=>m.get(h.path)).filter(Boolean)})()/g' apps/viewer/js/viewer-main.mjscheck again:
# grep -o -P 'this\.fileList=\(\(\)=>.*?\}\)\(\)' apps/viewer/js/viewer-main.mjsthis.fileList=(()=>{const m=new Map(L.map(P=>[P.filename,P]));return D.map(h=>m.get(h.path)).filter(Boolean)})()jonnykl commentedon Jul 10, 2026
Thanks @kokutoukiritsugu, I have adapted your temp fix for NC 34.0.1 (viewer 7.0.0-dev.0):
grep -o -E 'fileList=D.map[^,]*' apps/viewer/js/viewer-main.mjssed -i 's/this\.fileList=\([a-zA-Z]\+\)\.map([a-zA-Z]\+=>\([a-zA-Z]\+\)\.find([a-zA-Z]\+=>[a-zA-Z]\+\.filename===[a-zA-Z]\+\.path))/this.fileList=(()=>{const m=new Map(\2.map(T=>[T.filename,T]));return \1.map(h=>m.get(h.path)).filter(Boolean)})()/g' apps/viewer/js/viewer-main.mjsgrep -o -P 'this\.fileList=\(\(\)=>.*?\}\)\(\)' apps/viewer/js/viewer-main.mjstest(viewer): add e2e regression tests for the fixed issues
skjnldsv commentedon Oct 3, 2026
Fixed in the new viewer: it no longer matches every file against every other one when opening, so opening the viewer only gets linearly slower as folders grow.
Workaround fuer den Viewer-Haenger in grossen Ordnern (nextcloud/view…