Skip to content

Commit cd85aca

Browse files
Optimize dirList (#435)
* optimize dirlist * remove istanbul ignore * decrease concurrency to CPULength - 1 Co-authored-by: KaKa <23028015+climba03003@users.noreply.github.com> Signed-off-by: Gürgün Dayıoğlu <hey@gurgun.day> --------- Signed-off-by: Gürgün Dayıoğlu <hey@gurgun.day> Co-authored-by: KaKa <23028015+climba03003@users.noreply.github.com>
1 parent 160ec38 commit cd85aca

File tree

2 files changed

+58
-56
lines changed

2 files changed

+58
-56
lines changed

lib/dirList.js

Lines changed: 56 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,60 @@
11
'use strict'
22

3+
const os = require('node:os')
34
const path = require('node:path')
45
const fs = require('node:fs/promises')
5-
const pLimit = require('p-limit')
6+
const fastq = require('fastq')
7+
const fastqConcurrency = Math.max(1, os.cpus().length - 1)
68

79
const dirList = {
10+
_getExtendedInfo: async function (dir, info) {
11+
const depth = dir.split(path.sep).length
12+
const files = await fs.readdir(dir)
13+
14+
const worker = async (filename) => {
15+
const filePath = path.join(dir, filename)
16+
let stats
17+
try {
18+
stats = await fs.stat(filePath)
19+
} catch {
20+
return
21+
}
22+
23+
if (stats.isDirectory()) {
24+
info.totalFolderCount++
25+
filePath.split(path.sep).length === depth + 1 && info.folderCount++
26+
await dirList._getExtendedInfo(filePath, info)
27+
} else {
28+
info.totalSize += stats.size
29+
info.totalFileCount++
30+
filePath.split(path.sep).length === depth + 1 && info.fileCount++
31+
info.lastModified = Math.max(info.lastModified, stats.mtimeMs)
32+
}
33+
}
34+
const queue = fastq.promise(worker, fastqConcurrency)
35+
await Promise.all(files.map(filename => queue.push(filename)))
36+
},
37+
38+
/**
39+
* get extended info about a folder
40+
* @param {string} folderPath full path fs dir
41+
* @return {Promise<ExtendedInfo>}
42+
*/
43+
getExtendedInfo: async function (folderPath) {
44+
const info = {
45+
totalSize: 0,
46+
fileCount: 0,
47+
totalFileCount: 0,
48+
folderCount: 0,
49+
totalFolderCount: 0,
50+
lastModified: 0
51+
}
52+
53+
await dirList._getExtendedInfo(folderPath, info)
54+
55+
return info
56+
},
57+
858
/**
959
* get files and dirs from dir, or error
1060
* @param {string} dir full path fs dir
@@ -22,8 +72,7 @@ const dirList = {
2272
return entries
2373
}
2474

25-
const limit = pLimit(4)
26-
await Promise.all(files.map(filename => limit(async () => {
75+
const worker = async (filename) => {
2776
let stats
2877
try {
2978
stats = await fs.stat(path.join(dir, filename))
@@ -33,62 +82,15 @@ const dirList = {
3382
const entry = { name: filename, stats }
3483
if (stats.isDirectory()) {
3584
if (options.extendedFolderInfo) {
36-
entry.extendedInfo = await getExtendedInfo(path.join(dir, filename))
85+
entry.extendedInfo = await dirList.getExtendedInfo(path.join(dir, filename))
3786
}
3887
entries.dirs.push(entry)
3988
} else {
4089
entries.files.push(entry)
4190
}
42-
})))
43-
44-
async function getExtendedInfo (folderPath) {
45-
const depth = folderPath.split(path.sep).length
46-
let totalSize = 0
47-
let fileCount = 0
48-
let totalFileCount = 0
49-
let folderCount = 0
50-
let totalFolderCount = 0
51-
let lastModified = 0
52-
53-
async function walk (dir) {
54-
const files = await fs.readdir(dir)
55-
const limit = pLimit(4)
56-
await Promise.all(files.map(filename => limit(async () => {
57-
const filePath = path.join(dir, filename)
58-
let stats
59-
try {
60-
stats = await fs.stat(filePath)
61-
} catch {
62-
return
63-
}
64-
65-
if (stats.isDirectory()) {
66-
totalFolderCount++
67-
if (filePath.split(path.sep).length === depth + 1) {
68-
folderCount++
69-
}
70-
await walk(filePath)
71-
} else {
72-
totalSize += stats.size
73-
totalFileCount++
74-
if (filePath.split(path.sep).length === depth + 1) {
75-
fileCount++
76-
}
77-
lastModified = Math.max(lastModified, stats.mtimeMs)
78-
}
79-
})))
80-
}
81-
82-
await walk(folderPath)
83-
return {
84-
totalSize,
85-
fileCount,
86-
totalFileCount,
87-
folderCount,
88-
totalFolderCount,
89-
lastModified
90-
}
9191
}
92+
const queue = fastq.promise(worker, fastqConcurrency)
93+
await Promise.all(files.map(filename => queue.push(filename)))
9294

9395
entries.dirs.sort((a, b) => a.name.localeCompare(b.name))
9496
entries.files.sort((a, b) => a.name.localeCompare(b.name))
@@ -115,6 +117,7 @@ const dirList = {
115117
} catch {
116118
return reply.callNotFound()
117119
}
120+
118121
const format = reply.request.query.format || options.format
119122
if (format !== 'html') {
120123
if (options.jsonFormat !== 'extended') {
@@ -203,7 +206,6 @@ const dirList = {
203206
return new TypeError('The `list.render` option must be a function and is required with html format')
204207
}
205208
}
206-
207209
}
208210

209211
module.exports = dirList

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@
3535
"@fastify/send": "^2.0.0",
3636
"content-disposition": "^0.5.3",
3737
"fastify-plugin": "^4.0.0",
38-
"glob": "^10.3.4",
39-
"p-limit": "^3.1.0"
38+
"fastq": "^1.17.0",
39+
"glob": "^10.3.4"
4040
},
4141
"devDependencies": {
4242
"@fastify/compress": "^7.0.0",

0 commit comments

Comments
 (0)