readline-pager 0.2.6 → 0.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -10
- package/dist/main.cjs +33 -15
- package/dist/main.d.cts +1 -1
- package/dist/main.d.mts +1 -1
- package/dist/main.mjs +33 -15
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -100,7 +100,7 @@ Returns the next page or `null` when finished. Empty lines are preserved.
|
|
|
100
100
|
- A completely empty file (`0` bytes) produces `[""]` on the first read.
|
|
101
101
|
- A file with multiple empty lines returns each line as an empty string (e.g., `["", ""]` for two empty lines). Node.js `readline` may emit fewer or no `line` events in these cases.
|
|
102
102
|
|
|
103
|
-
### `pager.close(): void
|
|
103
|
+
### `pager.close(): Promise<void>`
|
|
104
104
|
|
|
105
105
|
Stops reading and releases resources immediately. Safe to call at any time.
|
|
106
106
|
|
|
@@ -118,21 +118,39 @@ Run the included benchmark:
|
|
|
118
118
|
|
|
119
119
|
```bash
|
|
120
120
|
# default run
|
|
121
|
-
|
|
121
|
+
npm run benchmark
|
|
122
122
|
|
|
123
123
|
# or customize with args
|
|
124
124
|
node test/_benchmark.ts --lines=20000 --page-size=500 --backward
|
|
125
125
|
```
|
|
126
126
|
|
|
127
127
|
> Test setup: generated text files with uuid, run on a fast NVMe machine with default options; values are averages from multiple runs. Results are machine-dependent.
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
128
|
+
>
|
|
129
|
+
> The **Average Throughput (MB/s)** is computed for two strategies: reading files line by line and page by page.
|
|
130
|
+
>
|
|
131
|
+
> In addition to _Node_, the two other popular JavaScript runtimes were also tested with `readline-pager`.
|
|
132
|
+
|
|
133
|
+
### Line by line
|
|
134
|
+
|
|
135
|
+
| Runtime / Method | 1M lines (35 MB) | 10M lines (353 MB) | 100M lines (3,529 MB) | 1,000M lines (35,286 MB) |
|
|
136
|
+
| ---------------- | ---------------: | -----------------: | --------------------: | -----------------------: |
|
|
137
|
+
| Node — node:line | 369 | 435 | 455 | 455 |
|
|
138
|
+
| Deno — node:line | 203 | 230 | 230 | 229 |
|
|
139
|
+
| Deno — deno:line | 738 | 901 | 915 | 809 |
|
|
140
|
+
| Bun — node:line | 246 | 279 | 283 | 280 |
|
|
141
|
+
| Bun — bun:line | 938 | 1,540 | 1,668 | 1,315 |
|
|
142
|
+
|
|
143
|
+
### Page by page
|
|
144
|
+
|
|
145
|
+
| Runtime / Method | 1M lines (35 MB) | 10M lines (353 MB) | 100M lines (3,529 MB) | 1,000M lines (35,286 MB) |
|
|
146
|
+
| --------------------- | ---------------: | -----------------: | --------------------: | -----------------------: |
|
|
147
|
+
| Node — readline-pager | 1,053 | 1,311 | 1,278 | 936 |
|
|
148
|
+
| Deno — deno:page | 852 | 909 | 908 | 783 |
|
|
149
|
+
| Deno — readline-pager | 1,131 | 1,268 | 1,271 | 911 |
|
|
150
|
+
| Bun — bun:page | 411 | 440 | 449 | 428 |
|
|
151
|
+
| Bun — readline-pager | 827 | 1,021 | 1,040 | 804 |
|
|
152
|
+
|
|
153
|
+
**Runtime Environment:** Node.js v25.6.1 & Bun v1.3.9 & Deno 2.6.10
|
|
136
154
|
|
|
137
155
|
---
|
|
138
156
|
|
package/dist/main.cjs
CHANGED
|
@@ -98,7 +98,10 @@ function createBackwardReader(filepath, options) {
|
|
|
98
98
|
closed = true;
|
|
99
99
|
done = true;
|
|
100
100
|
pageQueue.queue.length = 0;
|
|
101
|
-
if (fd)
|
|
101
|
+
if (fd) {
|
|
102
|
+
await fd.close();
|
|
103
|
+
fd = null;
|
|
104
|
+
}
|
|
102
105
|
}
|
|
103
106
|
return {
|
|
104
107
|
next,
|
|
@@ -113,10 +116,14 @@ function createBackwardReader(filepath, options) {
|
|
|
113
116
|
return lastLine;
|
|
114
117
|
},
|
|
115
118
|
async *[Symbol.asyncIterator]() {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
119
|
+
try {
|
|
120
|
+
while (true) {
|
|
121
|
+
const p = await next();
|
|
122
|
+
if (!p) break;
|
|
123
|
+
yield p;
|
|
124
|
+
}
|
|
125
|
+
} finally {
|
|
126
|
+
await close().catch(() => {});
|
|
120
127
|
}
|
|
121
128
|
}
|
|
122
129
|
};
|
|
@@ -187,7 +194,10 @@ function createForwardReader(filepath, options) {
|
|
|
187
194
|
closed = true;
|
|
188
195
|
done = true;
|
|
189
196
|
pageQueue.queue.length = 0;
|
|
190
|
-
if (fd)
|
|
197
|
+
if (fd) {
|
|
198
|
+
await fd.close();
|
|
199
|
+
fd = null;
|
|
200
|
+
}
|
|
191
201
|
}
|
|
192
202
|
return {
|
|
193
203
|
next,
|
|
@@ -202,10 +212,14 @@ function createForwardReader(filepath, options) {
|
|
|
202
212
|
return lastLine;
|
|
203
213
|
},
|
|
204
214
|
async *[Symbol.asyncIterator]() {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
215
|
+
try {
|
|
216
|
+
while (true) {
|
|
217
|
+
const p = await next();
|
|
218
|
+
if (!p) break;
|
|
219
|
+
yield p;
|
|
220
|
+
}
|
|
221
|
+
} finally {
|
|
222
|
+
await close();
|
|
209
223
|
}
|
|
210
224
|
}
|
|
211
225
|
};
|
|
@@ -247,7 +261,7 @@ function createWorkerReader(filepath, options) {
|
|
|
247
261
|
async function close() {
|
|
248
262
|
closed = true;
|
|
249
263
|
done = true;
|
|
250
|
-
worker.terminate();
|
|
264
|
+
await worker.terminate();
|
|
251
265
|
}
|
|
252
266
|
return {
|
|
253
267
|
next,
|
|
@@ -262,10 +276,14 @@ function createWorkerReader(filepath, options) {
|
|
|
262
276
|
return lastLine;
|
|
263
277
|
},
|
|
264
278
|
async *[Symbol.asyncIterator]() {
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
279
|
+
try {
|
|
280
|
+
while (true) {
|
|
281
|
+
const p = await next();
|
|
282
|
+
if (!p) break;
|
|
283
|
+
yield p;
|
|
284
|
+
}
|
|
285
|
+
} finally {
|
|
286
|
+
await close();
|
|
269
287
|
}
|
|
270
288
|
}
|
|
271
289
|
};
|
package/dist/main.d.cts
CHANGED
|
@@ -11,7 +11,7 @@ interface PagerOptions extends Partial<ReaderOptions> {
|
|
|
11
11
|
}
|
|
12
12
|
interface Pager extends AsyncIterable<string[]> {
|
|
13
13
|
next(): Promise<string[] | null>;
|
|
14
|
-
close(): void
|
|
14
|
+
close(): Promise<void>;
|
|
15
15
|
readonly lineCount: number;
|
|
16
16
|
readonly firstLine: string | null;
|
|
17
17
|
readonly lastLine: string | null;
|
package/dist/main.d.mts
CHANGED
|
@@ -11,7 +11,7 @@ interface PagerOptions extends Partial<ReaderOptions> {
|
|
|
11
11
|
}
|
|
12
12
|
interface Pager extends AsyncIterable<string[]> {
|
|
13
13
|
next(): Promise<string[] | null>;
|
|
14
|
-
close(): void
|
|
14
|
+
close(): Promise<void>;
|
|
15
15
|
readonly lineCount: number;
|
|
16
16
|
readonly firstLine: string | null;
|
|
17
17
|
readonly lastLine: string | null;
|
package/dist/main.mjs
CHANGED
|
@@ -102,7 +102,10 @@ function createBackwardReader(filepath, options) {
|
|
|
102
102
|
closed = true;
|
|
103
103
|
done = true;
|
|
104
104
|
pageQueue.queue.length = 0;
|
|
105
|
-
if (fd)
|
|
105
|
+
if (fd) {
|
|
106
|
+
await fd.close();
|
|
107
|
+
fd = null;
|
|
108
|
+
}
|
|
106
109
|
}
|
|
107
110
|
return {
|
|
108
111
|
next,
|
|
@@ -117,10 +120,14 @@ function createBackwardReader(filepath, options) {
|
|
|
117
120
|
return lastLine;
|
|
118
121
|
},
|
|
119
122
|
async *[Symbol.asyncIterator]() {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
123
|
+
try {
|
|
124
|
+
while (true) {
|
|
125
|
+
const p = await next();
|
|
126
|
+
if (!p) break;
|
|
127
|
+
yield p;
|
|
128
|
+
}
|
|
129
|
+
} finally {
|
|
130
|
+
await close().catch(() => {});
|
|
124
131
|
}
|
|
125
132
|
}
|
|
126
133
|
};
|
|
@@ -191,7 +198,10 @@ function createForwardReader(filepath, options) {
|
|
|
191
198
|
closed = true;
|
|
192
199
|
done = true;
|
|
193
200
|
pageQueue.queue.length = 0;
|
|
194
|
-
if (fd)
|
|
201
|
+
if (fd) {
|
|
202
|
+
await fd.close();
|
|
203
|
+
fd = null;
|
|
204
|
+
}
|
|
195
205
|
}
|
|
196
206
|
return {
|
|
197
207
|
next,
|
|
@@ -206,10 +216,14 @@ function createForwardReader(filepath, options) {
|
|
|
206
216
|
return lastLine;
|
|
207
217
|
},
|
|
208
218
|
async *[Symbol.asyncIterator]() {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
219
|
+
try {
|
|
220
|
+
while (true) {
|
|
221
|
+
const p = await next();
|
|
222
|
+
if (!p) break;
|
|
223
|
+
yield p;
|
|
224
|
+
}
|
|
225
|
+
} finally {
|
|
226
|
+
await close();
|
|
213
227
|
}
|
|
214
228
|
}
|
|
215
229
|
};
|
|
@@ -251,7 +265,7 @@ function createWorkerReader(filepath, options) {
|
|
|
251
265
|
async function close() {
|
|
252
266
|
closed = true;
|
|
253
267
|
done = true;
|
|
254
|
-
worker.terminate();
|
|
268
|
+
await worker.terminate();
|
|
255
269
|
}
|
|
256
270
|
return {
|
|
257
271
|
next,
|
|
@@ -266,10 +280,14 @@ function createWorkerReader(filepath, options) {
|
|
|
266
280
|
return lastLine;
|
|
267
281
|
},
|
|
268
282
|
async *[Symbol.asyncIterator]() {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
283
|
+
try {
|
|
284
|
+
while (true) {
|
|
285
|
+
const p = await next();
|
|
286
|
+
if (!p) break;
|
|
287
|
+
yield p;
|
|
288
|
+
}
|
|
289
|
+
} finally {
|
|
290
|
+
await close();
|
|
273
291
|
}
|
|
274
292
|
}
|
|
275
293
|
};
|
package/package.json
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "readline-pager",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.7",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"build": "tsdown",
|
|
6
6
|
"pretest": "npm run build",
|
|
7
7
|
"test": "node --test --experimental-test-coverage test/**/*.test.ts",
|
|
8
|
-
"prepublishOnly": "npm run build && npm run test"
|
|
8
|
+
"prepublishOnly": "npm run build && npm run test",
|
|
9
|
+
"benchmark": "node test/_benchmark.ts; bun test/_benchmark.ts; deno --allow-write --allow-read test/_benchmark.ts"
|
|
9
10
|
},
|
|
10
11
|
"devDependencies": {
|
|
11
12
|
"@types/bun": "~1.3.9",
|
|
13
|
+
"@types/deno": "~2.5.0",
|
|
12
14
|
"@types/node": "~25.3.0",
|
|
13
15
|
"prettier": "~3.8.1",
|
|
14
16
|
"prettier-plugin-organize-imports": "~4.3.0",
|