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 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, paginated file reader for Node.js with async iteration, prefetching, backward reading and optional worker support. `readline-pager` reads large text files page-by-page without loading the entire file into memory.
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 ~3x faster than Node.js `readline`
22
+ - ✅ Up to ~ faster than Node.js `readline`
22
23
  - ✅ ~97% test coverage & fully typed (TypeScript)
23
24
 
24
- > **Important:**
25
- > Performance is heavily dependent on the `chunkSize` option; ensure you fine-tune it for your specific I/O hardware. A setting of **64 KB** is typically a good starting point. Increasing it might gradually improve read speeds, usually reaching an optimal peak depending on your hardware's capabilities.
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
- **Recommended for highest throughput:**
51
+ // Sync iteration
52
+ for (const page of pager) {
53
+ }
53
54
 
54
- ```ts
55
+ // Manual next
55
56
  while (true) {
56
57
  const page = await pager.next();
57
58
  if (!page) break;
58
59
  }
59
60
 
60
- // or
61
+ // Manual nextSync (also with condition variation)
61
62
  let page;
62
- while ((page = await pager.next()) !== null) {}
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: 1
75
+ prefetch?: number, // default: 8
78
76
  backward?: boolean, // default: false
79
- useWorker?: boolean, // default: false (forward only)
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` — max number of pages buffered internally. Not required for typical use; tuning has little effect once the engine is optimized.
87
- - `backward` — read file from end → start (not supported with `useWorker`).
88
- - `useWorker` — offload parsing to a worker thread (forward only).
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 or `null` when finished. Empty lines are preserved.
94
+ Returns the next page asynchronously.
97
95
 
98
- **Note:** Unlike Node.js `readline`, which may skip empty files or leading empty lines, `readline-pager` always returns all lines.
96
+ Returns `null` when the end of the file is reached.
99
97
 
100
- - A completely empty file (`0` bytes) produces `[""]` on the first read.
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
- ### `pager.close(): void`
100
+ ---
101
+
102
+ ### `pager.nextSync(): string[] | null`
103
+
104
+ Synchronous version of `pager.next()`.
104
105
 
105
- Stops reading and releases resources immediately. Safe to call at any time.
106
+ Returns the next page immediately or `null` when the end of the file is reached.
107
+
108
+ ---
106
109
 
107
- ### Read-only properties
110
+ ### `pager.close(): Promise<void>`
108
111
 
109
- - `pager.lineCount` lines emitted so far
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
- node test/_benchmark.ts
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
- | Lines | File MB | Node `readline` (MB/s) | Bun streaming (MB/s) | `readline-pager` (Node) (MB/s) |
130
- | -----: | -------: | ---------------------: | -------------------: | -----------------------------: |
131
- | 10M | 352.86 | ~423 | ~296 | **~1,327** |
132
- | 100M | 3528.59 | ~441 | ~298 | **~1,378** |
133
- | 1,000M | 35285.95 | ~426 | ~294 | **~1,168** |
134
-
135
- **Runtime Environment:** Node.js v25.6.1 & Bun v1.3.9
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