@@ -40,9 +40,8 @@ class Dir { |
40 | 40 | #options; |
41 | 41 | #readPromisified; |
42 | 42 | #closePromisified; |
43 | | - // Either `null` or an Array of pending operations (= functions to be called |
44 | | - // once the current operation is done). |
45 | 43 | #operationQueue = null; |
| 44 | + #handlerQueue = []; |
46 | 45 |
|
47 | 46 | constructor(handle, path, options) { |
48 | 47 | if (handle == null) throw new ERR_MISSING_ARGS('handle'); |
@@ -67,6 +66,33 @@ class Dir { |
67 | 66 | return this.#path; |
68 | 67 | } |
69 | 68 |
|
| 69 | + #processHandlerQueue() { |
| 70 | + while (this.#handlerQueue.length > 0) { |
| 71 | + const handler = ArrayPrototypeShift(this.#handlerQueue); |
| 72 | + const { handle, path } = handler; |
| 73 | + |
| 74 | + const result = handle.read( |
| 75 | + this.#options.encoding, |
| 76 | + this.#options.bufferSize, |
| 77 | + ); |
| 78 | + |
| 79 | + if (result !== null) { |
| 80 | + this.processReadResult(path, result); |
| 81 | + if (result.length > 0) { |
| 82 | + ArrayPrototypePush(this.#handlerQueue, handler); |
| 83 | + } |
| 84 | + } else { |
| 85 | + handle.close(); |
| 86 | + } |
| 87 | + |
| 88 | + if (this.#bufferedEntries.length > 0) { |
| 89 | + break; |
| 90 | + } |
| 91 | + } |
| 92 | + |
| 93 | + return this.#bufferedEntries.length > 0; |
| 94 | + } |
| 95 | + |
70 | 96 | read(callback) { |
71 | 97 | return this.#readImpl(true, callback); |
72 | 98 | } |
@@ -89,7 +115,7 @@ class Dir { |
89 | 115 | return; |
90 | 116 | } |
91 | 117 |
|
92 | | - if (this.#bufferedEntries.length > 0) { |
| 118 | + if (this.#processHandlerQueue()) { |
93 | 119 | try { |
94 | 120 | const dirent = ArrayPrototypeShift(this.#bufferedEntries); |
95 | 121 |
|
@@ -159,25 +185,11 @@ class Dir { |
159 | 185 | this.#options.encoding, |
160 | 186 | ); |
161 | 187 |
|
162 | | - // Terminate early, since it's already thrown. |
163 | 188 | if (handle === undefined) { |
164 | 189 | return; |
165 | 190 | } |
166 | 191 |
|
167 | | - // Fully read the directory and buffer the entries. |
168 | | - // This is a naive solution and for very large sub-directories |
169 | | - // it can even block the event loop. Essentially, `bufferSize` is |
170 | | - // not respected for recursive mode. This is a known limitation. |
171 | | - // Issue to fix: https://github.com/nodejs/node/issues/55764 |
172 | | - let result; |
173 | | - while ((result = handle.read( |
174 | | - this.#options.encoding, |
175 | | - this.#options.bufferSize, |
176 | | - ))) { |
177 | | - this.processReadResult(path, result); |
178 | | - } |
179 | | - |
180 | | - handle.close(); |
| 192 | + ArrayPrototypePush(this.#handlerQueue, { handle, path }); |
181 | 193 | } |
182 | 194 |
|
183 | 195 | readSync() { |
@@ -189,7 +201,7 @@ class Dir { |
189 | 201 | throw new ERR_DIR_CONCURRENT_OPERATION(); |
190 | 202 | } |
191 | 203 |
|
192 | | - if (this.#bufferedEntries.length > 0) { |
| 204 | + if (this.#processHandlerQueue()) { |
193 | 205 | const dirent = ArrayPrototypeShift(this.#bufferedEntries); |
194 | 206 | if (this.#options.recursive && dirent.isDirectory()) { |
195 | 207 | this.readSyncRecursive(dirent); |
@@ -216,15 +228,13 @@ class Dir { |
216 | 228 | } |
217 | 229 |
|
218 | 230 | close(callback) { |
219 | | - // Promise |
220 | 231 | if (callback === undefined) { |
221 | 232 | if (this.#closed === true) { |
222 | 233 | return PromiseReject(new ERR_DIR_CLOSED()); |
223 | 234 | } |
224 | 235 | return this.#closePromisified(); |
225 | 236 | } |
226 | 237 |
|
227 | | - // callback |
228 | 238 | validateFunction(callback, 'callback'); |
229 | 239 |
|
230 | 240 | if (this.#closed === true) { |
@@ -239,6 +249,11 @@ class Dir { |
239 | 249 | return; |
240 | 250 | } |
241 | 251 |
|
| 252 | + while (this.#handlerQueue.length > 0) { |
| 253 | + const handler = ArrayPrototypeShift(this.#handlerQueue); |
| 254 | + handler.handle.close(); |
| 255 | + } |
| 256 | + |
242 | 257 | this.#closed = true; |
243 | 258 | const req = new FSReqCallback(); |
244 | 259 | req.oncomplete = callback; |
@@ -254,6 +269,11 @@ class Dir { |
254 | 269 | throw new ERR_DIR_CONCURRENT_OPERATION(); |
255 | 270 | } |
256 | 271 |
|
| 272 | + while (this.#handlerQueue.length > 0) { |
| 273 | + const handler = ArrayPrototypeShift(this.#handlerQueue); |
| 274 | + handler.handle.close(); |
| 275 | + } |
| 276 | + |
257 | 277 | this.#closed = true; |
258 | 278 | this.#handle.close(); |
259 | 279 | } |
|