readline-pager 0.2.6 → 0.3.0
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 +65 -40
- package/dist/main.cjs +407 -148
- package/dist/main.d.cts +3 -5
- package/dist/main.d.mts +3 -5
- package/dist/main.mjs +402 -147
- package/dist/worker.cjs +15 -13
- package/dist/worker.mjs +15 -13
- package/package.json +15 -7
- package/prebuilds/linux-x64/readline-pager.node +0 -0
package/README.md
CHANGED
|
@@ -12,17 +12,18 @@
|
|
|
12
12
|
<img src="https://img.shields.io/github/stars/devmor-j/readline-pager" alt="stars">
|
|
13
13
|
</p>
|
|
14
14
|
|
|
15
|
-
⚡ Memory-efficient
|
|
15
|
+
⚡ Memory-efficient paginated file reader for Node.js with async and sync iteration, prefetching, backward reading, and optional worker support. `readline-pager` reads large text files page-by-page without loading the entire file into memory.
|
|
16
16
|
|
|
17
17
|
- ✅ Zero dependencies
|
|
18
18
|
- ✅ Async iterator (`for await...of`) + manual `next()` API
|
|
19
|
+
- ✅ Sync iterator (`for...of`) + manual `nextSync()` API
|
|
19
20
|
- ✅ Forward & backward reading (EOF → BOF)
|
|
20
21
|
- ✅ Optional worker thread mode (forward only)
|
|
21
|
-
- ✅ Up to ~
|
|
22
|
+
- ✅ Up to ~3× faster than Node.js `readline`
|
|
22
23
|
- ✅ ~97% test coverage & fully typed (TypeScript)
|
|
23
24
|
|
|
24
|
-
> **Important:**
|
|
25
|
-
> Performance
|
|
25
|
+
> **Important:**
|
|
26
|
+
> Performance depends heavily on the `chunkSize` option. Tune it for your specific I/O hardware. A value of **64 KB** is usually a good starting point. Increasing it may gradually improve throughput until reaching the optimal point for your hardware.
|
|
26
27
|
|
|
27
28
|
---
|
|
28
29
|
|
|
@@ -42,31 +43,28 @@ import { createPager } from "readline-pager";
|
|
|
42
43
|
|
|
43
44
|
const pager = createPager("./bigfile.txt");
|
|
44
45
|
|
|
46
|
+
// Async iteration
|
|
45
47
|
for await (const page of pager) {
|
|
46
48
|
console.log(page[0]); // first line of the current page
|
|
47
49
|
}
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
---
|
|
51
50
|
|
|
52
|
-
|
|
51
|
+
// Sync iteration
|
|
52
|
+
for (const page of pager) {
|
|
53
|
+
}
|
|
53
54
|
|
|
54
|
-
|
|
55
|
+
// Manual next
|
|
55
56
|
while (true) {
|
|
56
57
|
const page = await pager.next();
|
|
57
58
|
if (!page) break;
|
|
58
59
|
}
|
|
59
60
|
|
|
60
|
-
//
|
|
61
|
+
// Manual nextSync (also with condition variation)
|
|
61
62
|
let page;
|
|
62
|
-
while ((page =
|
|
63
|
+
while ((page = pager.nextSync()) !== null) {
|
|
64
|
+
console.log(page[0]);
|
|
65
|
+
}
|
|
63
66
|
```
|
|
64
67
|
|
|
65
|
-
- `while + next()` is the fastest iteration method (avoids extra async-iterator overhead).
|
|
66
|
-
- `for await of` is more ergonomic and convenient.
|
|
67
|
-
|
|
68
|
-
---
|
|
69
|
-
|
|
70
68
|
## ⚙️ Options
|
|
71
69
|
|
|
72
70
|
```ts
|
|
@@ -74,18 +72,18 @@ createPager(filepath, {
|
|
|
74
72
|
chunkSize?: number, // default: 64 * 1024 (64 KiB)
|
|
75
73
|
pageSize?: number, // default: 1_000
|
|
76
74
|
delimiter?: string, // default: "\n"
|
|
77
|
-
prefetch?: number, // default:
|
|
75
|
+
prefetch?: number, // default: 8
|
|
78
76
|
backward?: boolean, // default: false
|
|
79
|
-
useWorker?: boolean, // default: false
|
|
77
|
+
useWorker?: boolean, // default: false
|
|
80
78
|
});
|
|
81
79
|
```
|
|
82
80
|
|
|
83
81
|
- `chunkSize` — number of bytes read per I/O operation.
|
|
84
82
|
- `pageSize` — number of lines per page.
|
|
85
83
|
- `delimiter` — line separator.
|
|
86
|
-
- `prefetch` —
|
|
87
|
-
- `backward` — read file from end → start (not supported with `useWorker`).
|
|
88
|
-
- `useWorker` — offload
|
|
84
|
+
- `prefetch` — maximum number of pages buffered internally.
|
|
85
|
+
- `backward` — read the file from end → start (not supported with `useWorker`).
|
|
86
|
+
- `useWorker` — offload reading to a worker thread (forward reading only).
|
|
89
87
|
|
|
90
88
|
---
|
|
91
89
|
|
|
@@ -93,46 +91,73 @@ createPager(filepath, {
|
|
|
93
91
|
|
|
94
92
|
### `pager.next(): Promise<string[] | null>`
|
|
95
93
|
|
|
96
|
-
Returns the next page
|
|
94
|
+
Returns the next page asynchronously.
|
|
97
95
|
|
|
98
|
-
|
|
96
|
+
Returns `null` when the end of the file is reached.
|
|
99
97
|
|
|
100
|
-
|
|
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.
|
|
98
|
+
Empty lines are preserved.
|
|
102
99
|
|
|
103
|
-
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
### `pager.nextSync(): string[] | null`
|
|
103
|
+
|
|
104
|
+
Synchronous version of `pager.next()`.
|
|
104
105
|
|
|
105
|
-
|
|
106
|
+
Returns the next page immediately or `null` when the end of the file is reached.
|
|
107
|
+
|
|
108
|
+
---
|
|
106
109
|
|
|
107
|
-
###
|
|
110
|
+
### `pager.close(): Promise<void>`
|
|
108
111
|
|
|
109
|
-
|
|
110
|
-
- `pager.firstLine` — first emitted line (available after first read)
|
|
111
|
-
- `pager.lastLine` — last emitted line (updated per page)
|
|
112
|
+
Stops reading and releases resources asynchronously. Safe to call at any time.
|
|
112
113
|
|
|
113
114
|
---
|
|
114
115
|
|
|
116
|
+
**Note:**
|
|
117
|
+
Unlike Node.js `readline`, which may skip empty files or leading empty lines, `readline-pager` always returns all lines.
|
|
118
|
+
|
|
119
|
+
- A completely empty file (`0` bytes) produces `[""]` on the first read.
|
|
120
|
+
- A file containing multiple empty lines returns each line as an empty string (for example `["", ""]` for two empty lines).
|
|
121
|
+
|
|
115
122
|
## 📊 Benchmark
|
|
116
123
|
|
|
117
124
|
Run the included benchmark:
|
|
118
125
|
|
|
119
126
|
```bash
|
|
120
127
|
# default run
|
|
121
|
-
|
|
128
|
+
npm run benchmark
|
|
122
129
|
|
|
123
130
|
# or customize with args
|
|
124
131
|
node test/_benchmark.ts --lines=20000 --page-size=500 --backward
|
|
125
132
|
```
|
|
126
133
|
|
|
127
134
|
> 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
|
-
|
|
135
|
+
>
|
|
136
|
+
> The **Average Throughput (MB/s)** is computed for two strategies: reading files line by line and page by page.
|
|
137
|
+
>
|
|
138
|
+
> In addition to _Node_, the two other popular JavaScript runtimes were also tested with `readline-pager`.
|
|
139
|
+
|
|
140
|
+
### Line by line
|
|
141
|
+
|
|
142
|
+
| Runtime / Method | 1M lines (35 MB) | 10M lines (353 MB) | 100M lines (3,529 MB) | 1,000M lines (35,286 MB) |
|
|
143
|
+
| ---------------- | ---------------: | -----------------: | --------------------: | -----------------------: |
|
|
144
|
+
| Node — node:line | 369 | 435 | 455 | 455 |
|
|
145
|
+
| Deno — node:line | 203 | 230 | 230 | 229 |
|
|
146
|
+
| Deno — deno:line | 738 | 901 | 915 | 809 |
|
|
147
|
+
| Bun — node:line | 246 | 279 | 283 | 280 |
|
|
148
|
+
| Bun — bun:line | 938 | 1,540 | 1,668 | 1,315 |
|
|
149
|
+
|
|
150
|
+
### Page by page
|
|
151
|
+
|
|
152
|
+
| Runtime / Method | 1M lines (35 MB) | 10M lines (353 MB) | 100M lines (3,529 MB) | 1,000M lines (35,286 MB) |
|
|
153
|
+
| --------------------- | ---------------: | -----------------: | --------------------: | -----------------------: |
|
|
154
|
+
| Node — readline-pager | 1,053 | 1,311 | 1,278 | 936 |
|
|
155
|
+
| Deno — deno:page | 852 | 909 | 908 | 783 |
|
|
156
|
+
| Deno — readline-pager | 1,131 | 1,268 | 1,271 | 911 |
|
|
157
|
+
| Bun — bun:page | 411 | 440 | 449 | 428 |
|
|
158
|
+
| Bun — readline-pager | 827 | 1,021 | 1,040 | 804 |
|
|
159
|
+
|
|
160
|
+
**Runtime Environment:** Node.js v25.6.1 & Bun v1.3.9 & Deno 2.6.10
|
|
136
161
|
|
|
137
162
|
---
|
|
138
163
|
|