Skip to content

Opening an image in a directory with many files is very slow #3015

Closed

Description

@jonnykl

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

viewer/src/views/Viewer.vue

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

viewer/src/views/Viewer.vue

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:

  1. Open an image in a directory with many (~10k) images
  2. Wait until the prev/next buttons appear

Desktop (please complete the following information):

  • OS: Ubuntu 22.04
  • Browser Firefox 144.0.2

Activity

  1. added
    bugSomething isn't working
    0. Needs triagePending approval or rejection. This issue is pending approval.
    on Nov 10, 2025
  2. skjnldsv commented on Nov 26, 2025

    @skjnldsv
    Member

    Should be fixed once we have #2989

  3. kokutoukiritsugu commented on May 27, 2026

    @kokutoukiritsugu

    viewer 6.0.0 temp fix:

    check the mjs file:

    # grep -o -E '[a-zA-Z0-9_$]+\.fileList=\(\(\)=>[^)]+\)' apps/viewer/js/viewer-main.mjs
    this.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.mjs

    check again:

    # grep -o -P 'this\.fileList=\(\(\)=>.*?\}\)\(\)' apps/viewer/js/viewer-main.mjs
    this.fileList=(()=>{const m=new Map(L.map(P=>[P.filename,P]));return D.map(h=>m.get(h.path)).filter(Boolean)})()

  4. jonnykl commented on Jul 10, 2026

    @jonnykl
    Author

    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.mjs

    sed -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.mjs

    grep -o -P 'this\.fileList=\(\(\)=>.*?\}\)\(\)' apps/viewer/js/viewer-main.mjs

  5. skjnldsv commented on Oct 3, 2026

    @skjnldsv
    Member

    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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    0. Needs triagePending approval or rejection. This issue is pending approval.bugSomething isn't working

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions