Created
September 6, 2022 14:58
-
-
Save tksst/f046710b142ef57e50371fadd2d974c7 to your computer and use it in GitHub Desktop.
recursiveReaddir.mjs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import fs from "node:fs/promises"; | |
import path from "node:path"; | |
function isNil(it) { | |
return it === null || it === undefined; | |
} | |
function isNotNil(it) { | |
return it !== null && it !== undefined; | |
} | |
class Timer { | |
constructor() { | |
this.t = performance.now(); | |
} | |
elapsed() { | |
return performance.now() - this.t; | |
} | |
log() { | |
console.log(performance.now() - this.t); | |
} | |
} | |
async function* recursiveReaddir(dir) { | |
const dirents = await fs.readdir(dir, { withFileTypes: true }); | |
for (const dirent of dirents) { | |
const joined = path.join(dir, dirent.name); | |
if (dirent.isDirectory()) { | |
yield* recursiveReaddir(joined); | |
} else { | |
yield joined; | |
} | |
} | |
} | |
async function* recursiveReaddirNative(dir) { | |
for await (const dirent of await fs.opendir(dir, { bufferSize: 100 })) { | |
const joined = path.join(dir, dirent.name); | |
if (dirent.isDirectory()) { | |
yield* recursiveReaddirNative(joined); | |
} else { | |
yield joined; | |
} | |
} | |
} | |
class RelativePathDirent { | |
#dirent; | |
#path; | |
constructor(dirent, path) { | |
this.#dirent = dirent; | |
this.#path = path; | |
} | |
isDirectory() { | |
return this.#dirent.isDirectory(); | |
} | |
name() { | |
return this.#dirent.name(); | |
} | |
relativePath() { | |
return path.join(this.#path, this.#dirent.name); | |
} | |
} | |
class RelativePathDir { | |
#path; | |
#handle; | |
static async create(path) { | |
return new RelativePathDir(path, await fs.opendir(path)); | |
} | |
constructor(path, handle) { | |
this.#path = path; | |
this.#handle = handle; | |
} | |
async read() { | |
const x = await this.#handle.read(); | |
if (isNil(x)) { | |
return undefined; | |
} | |
return new RelativePathDirent(x, this.#path); | |
} | |
async close() { | |
return this.#handle.close(); | |
} | |
} | |
class Dir { | |
#queue; | |
static async create(path) { | |
return new Dir(RelativePathDir.create(path)); | |
} | |
constructor(handle) { | |
this.#queue = [handle]; | |
} | |
async read() { | |
while (true) { | |
if (this.#queue.length === 0) { | |
return undefined; | |
} | |
const handle = await this.#queue.pop(); | |
const dirent = await handle.read(); | |
if (isNil(dirent)) { | |
handle.close(); | |
continue; | |
} | |
this.#queue.push(handle); | |
if (dirent.isDirectory()) { | |
this.#queue.push(RelativePathDir.create(dirent.relativePath())); | |
continue; | |
} | |
return dirent.relativePath(); | |
} | |
} | |
async readMulti(n) { | |
const ar = []; | |
for (let i = 0; i < n; ++i) { | |
ar.push(this.read()); | |
} | |
const result = await Promise.all(ar); | |
if (isNil(result[n - 1])) { | |
return result.filter(isNotNil); | |
} | |
return result; | |
} | |
} | |
async function* recursiveReaddirOwnImpl(path) { | |
const d = await Dir.create(path); | |
while (true) { | |
const x = await d.read(); | |
if (isNil(x)) { | |
break; | |
} | |
yield x; | |
} | |
} | |
async function* recursiveReaddirOwnImplMulti(path) { | |
const d = await Dir.create(path); | |
while (true) { | |
const x = await d.readMulti(100); | |
if (x.length === 0) { | |
break; | |
} | |
yield* x; | |
} | |
} | |
let t; | |
let d; | |
// t = new Timer(); | |
// for await (const x of await recursiveReaddirOwnImpl("../")) { | |
// console.log(x); | |
// } | |
// t.log(); | |
t = new Timer(); | |
for await (const x of await recursiveReaddirOwnImplMulti("../")) { | |
// console.log(x); | |
} | |
t.log(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment