Node.js v26.0.0 說明文件
- Node.js v26.0.0
- 目錄
- Readline
- 類別:
InterfaceConstructor- 事件:
'close' - 事件:
'error' - 事件:
'line' - 事件:
'history' - 事件:
'pause' - 事件:
'resume' - 事件:
'SIGCONT' - 事件:
'SIGINT' - 事件:
'SIGTSTP' rl.close()rl[Symbol.dispose]()rl.pause()rl.prompt([preserveCursor])rl.resume()rl.setPrompt(prompt)rl.getPrompt()rl.write(data[, key])rl[Symbol.asyncIterator]()rl.linerl.cursorrl.getCursorPos()
- 事件:
- Promises API
- Callback API
readline.emitKeypressEvents(stream[, interface])- 範例:微型 CLI
- 範例:逐行讀取檔案串流
- TTY 快捷鍵
- 類別:
- Readline
- 索引
- 關於此說明文件
- 用法與範例
- 斷言測試
- 非同步內容追蹤
- Async hooks
- Buffer
- C++ 擴充套件
- 使用 Node-API 的 C/C++ 擴充套件
- C++ 嵌入器 API
- 子程序
- 叢集
- 命令列選項
- Console
- Crypto
- 除錯器
- 棄用的 API
- Diagnostics Channel
- DNS
- 網域 (Domain)
- 環境變數
- 錯誤
- 事件
- 檔案系統
- 全域變數
- HTTP
- HTTP/2
- HTTPS
- 檢查器
- 國際化
- 模組:CommonJS 模組
- 模組:ECMAScript 模組
- 模組:
node:moduleAPI - 模組:套件
- 模組:TypeScript
- Net
- Iterable Streams API
- OS
- Path
- 效能勾子 (Performance hooks)
- 權限
- 程序
- Punycode
- 查詢字串
- Readline
- REPL
- 報告
- 單一可執行應用程式
- SQLite
- Stream
- 字串解碼器
- 測試執行器
- 計時器
- TLS/SSL
- 追蹤事件
- TTY
- UDP/資料報
- URL
- 公用工具
- V8
- VM
- WASI
- Web Crypto API
- Web Streams API
- 工作執行緒
- Zlib
- Zlib 可反覆運算壓縮
- 其他版本
- 選項
Readline#
穩定度:2 - 穩定
node:readline 模組提供了一個介面,用於逐行讀取來自可讀取 (Readable) 串流(例如 process.stdin)的資料。
要使用基於 Promise 的 API
import * as readline from 'node:readline/promises';const readline = require('node:readline/promises');
要使用回呼 (callback) 與同步 (sync) API
import * as readline from 'node:readline';const readline = require('node:readline');
以下簡單範例說明了 node:readline 模組的基本用法。
import * as readline from 'node:readline/promises'; import { stdin as input, stdout as output } from 'node:process'; const rl = readline.createInterface({ input, output }); const answer = await rl.question('What do you think of Node.js? '); console.log(`Thank you for your valuable feedback: ${answer}`); rl.close();const readline = require('node:readline'); const { stdin: input, stdout: output } = require('node:process'); const rl = readline.createInterface({ input, output }); rl.question('What do you think of Node.js? ', (answer) => { // TODO: Log the answer in a database console.log(`Thank you for your valuable feedback: ${answer}`); rl.close(); });
這段程式碼被調用後,Node.js 應用程式不會終止,直到 readline.Interface 被關閉,因為介面會等待 input 串流接收資料。
類別:InterfaceConstructor#
- 繼承自:
<EventEmitter>
InterfaceConstructor 類別的執行個體是使用 readlinePromises.createInterface() 或 readline.createInterface() 方法建構的。每個執行個體都與單個 input 可讀取 串流和單個 output 可寫入 串流相關聯。output 串流用於為 input 串流上抵達並讀取的輸入列印提示訊息。
事件:'close'#
當發生以下情況之一時,會觸發 'close' 事件
rl.close()方法被呼叫,且InterfaceConstructor執行個體已放棄對input和output串流的控制;input串流接收到其'end'事件;input串流接收到 Ctrl+D 以發出傳輸結束 (EOT) 信號;input串流接收到 Ctrl+C 以發出SIGINT信號,且InterfaceConstructor執行個體上未註冊任何'SIGINT'事件監聽器。
呼叫監聽器函式時不傳遞任何參數。
一旦觸發 'close' 事件,InterfaceConstructor 執行個體即告完成。
事件:'error'#
當與 node:readline Interface 相關聯的 input 串流發生錯誤時,會觸發 'error' 事件。
監聽器函式在呼叫時會傳入一個 Error 物件作為唯一參數。
事件:'line'#
每當 input 串流接收到換行輸入(\n、\r 或 \r\n)時,就會觸發 'line' 事件。這通常發生在使用者按下 Enter 或 Return 鍵時。
如果從串流中讀取了新資料,且該串流在結束時沒有最終的換行標記,也會觸發 'line' 事件。
呼叫監聽器函式時,會傳入一個包含接收到的單行輸入字串。
rl.on('line', (input) => {
console.log(`Received: ${input}`);
});
事件:'history'#
每當歷史紀錄陣列發生變化時,就會觸發 'history' 事件。
監聽器函式在呼叫時會傳入包含歷史紀錄的陣列。它將反映所有變更,包括因 historySize 和 removeHistoryDuplicates 而新增或移除的行。
主要目的是允許監聽器持久化歷史紀錄。監聽器也可以更改歷史紀錄物件,這對於防止某些行(例如密碼)被加入歷史紀錄非常有用。
rl.on('history', (history) => {
console.log(`Received: ${history}`);
});
事件:'pause'#
當發生以下情況之一時,會觸發 'pause' 事件
呼叫監聽器函式時不傳遞任何參數。
rl.on('pause', () => {
console.log('Readline paused.');
});
事件:'resume'#
每當 input 串流恢復時,都會觸發 'resume' 事件。
呼叫監聽器函式時不傳遞任何參數。
rl.on('resume', () => {
console.log('Readline resumed.');
});
事件:'SIGCONT'#
當先前使用 Ctrl+Z(即 SIGTSTP)移至背景的 Node.js 程序隨後使用 fg(1p) 帶回前景時,會觸發 'SIGCONT' 事件。
如果 input 串流在 SIGTSTP 請求之前就已暫停,則不會觸發此事件。
呼叫監聽器函式時不傳遞任何參數。
rl.on('SIGCONT', () => {
// `prompt` will automatically resume the stream
rl.prompt();
});
Windows 不支援 'SIGCONT' 事件。
事件:'SIGINT'#
每當 input 串流接收到 Ctrl+C 輸入(通常稱為 SIGINT)時,就會觸發 'SIGINT' 事件。如果當 input 串流接收到 SIGINT 時沒有註冊 'SIGINT' 事件監聽器,則會觸發 'pause' 事件。
呼叫監聽器函式時不傳遞任何參數。
rl.on('SIGINT', () => {
rl.question('Are you sure you want to exit? ', (answer) => {
if (answer.match(/^y(es)?$/i)) rl.pause();
});
});
事件:'SIGTSTP'#
當 input 串流接收到 Ctrl+Z 輸入(通常稱為 SIGTSTP)時,就會觸發 'SIGTSTP' 事件。如果當 input 串流接收到 SIGTSTP 時沒有註冊 'SIGTSTP' 事件監聽器,Node.js 程序將被送到背景。
當程式使用 fg(1p) 恢復時,將觸發 'pause' 和 'SIGCONT' 事件。這些事件可用於恢復 input 串流。
如果程序被送到背景之前 input 就已暫停,則不會觸發 'pause' 和 'SIGCONT' 事件。
呼叫監聽器函式時不傳遞任何參數。
rl.on('SIGTSTP', () => {
// This will override SIGTSTP and prevent the program from going to the
// background.
console.log('Caught SIGTSTP.');
});
Windows 不支援 'SIGTSTP' 事件。
rl.close()#
rl.close() 方法會關閉 InterfaceConstructor 執行個體並放棄對 input 和 output 串流的控制。呼叫時,會觸發 'close' 事件。
呼叫 rl.close() 不會立即停止 InterfaceConstructor 執行個體觸發其他事件(包括 'line')。
rl[Symbol.dispose]()#
rl.close() 的別名。
rl.pause()#
rl.pause() 方法會暫停 input 串流,以便在需要時稍後恢復。
呼叫 rl.pause() 不會立即暫停 InterfaceConstructor 執行個體觸發其他事件(包括 'line')。
rl.prompt([preserveCursor])#
preserveCursor<boolean>如果為true,則防止游標位置被重置為0。
rl.prompt() 方法會在 output 的新行寫入 InterfaceConstructor 執行個體設定的 prompt,以便為使用者提供提供輸入的新位置。
呼叫時,如果 input 串流已暫停,rl.prompt() 會將其恢復。
如果建立 InterfaceConstructor 時將 output 設定為 null 或 undefined,則不會寫入提示訊息。
rl.resume()#
如果 input 串流已暫停,rl.resume() 方法會將其恢復。
rl.setPrompt(prompt)#
prompt<string>
rl.setPrompt() 方法設定每當呼叫 rl.prompt() 時將寫入 output 的提示訊息。
rl.getPrompt()#
- 回傳:
<string>目前的提示字串
rl.getPrompt() 方法回傳 rl.prompt() 使用的目前提示訊息。
rl.write(data[, key])#
rl.write() 方法會將 data 或由 key 識別的按鍵序列寫入 output。僅當 output 為 TTY 文字終端機時才支援 key 參數。有關按鍵組合列表,請參見 TTY 快捷鍵。
如果指定了 key,則忽略 data。
呼叫時,如果 input 串流已暫停,rl.write() 會將其恢復。
如果建立 InterfaceConstructor 時將 output 設定為 null 或 undefined,則不會寫入 data 和 key。
rl.write('Delete this!');
// Simulate Ctrl+U to delete the line written previously
rl.write(null, { ctrl: true, name: 'u' });
rl.write() 方法會將資料寫入 readline Interface 的 input,就如同是由使用者提供的一樣。
rl[Symbol.asyncIterator]()#
建立一個 AsyncIterator 物件,以字串形式疊代輸入串流中的每一行。此方法允許透過 for await...of 迴圈對 InterfaceConstructor 物件進行非同步疊代。
輸入串流中的錯誤不會被轉發。
如果迴圈使用 break、throw 或 return 終止,則會呼叫 rl.close()。換句話說,疊代 InterfaceConstructor 將始終完整消耗輸入串流。
效能與傳統的 'line' 事件 API 不同。對於效能敏感的應用程式,請改用 'line'。
async function processLineByLine() {
const rl = readline.createInterface({
// ...
});
for await (const line of rl) {
// Each line in the readline input will be successively available here as
// `line`.
}
}
readline.createInterface() 調用後將開始消耗輸入串流。在介面建立與非同步疊代之間進行非同步操作可能會導致遺漏某些行。
rl.line#
- 類型:
<string>
Node 目前正在處理的輸入資料。
這可以用於從 TTY 串流收集輸入時,在觸發 line 事件之前檢索到目前為止已處理的目前值。一旦觸發 line 事件,此屬性將成為空字串。
請注意,如果在執行期間修改該值而未同時控制 rl.cursor,可能會產生意想不到的後果。
如果不使用 TTY 串流作為輸入,請使用 'line' 事件。
一個可能的用例如下:
const values = ['lorem ipsum', 'dolor sit amet'];
const rl = readline.createInterface(process.stdin);
const showResults = debounce(() => {
console.log(
'\n',
values.filter((val) => val.startsWith(rl.line)).join(' '),
);
}, 300);
process.stdin.on('keypress', (c, k) => {
showResults();
});
rl.cursor#
- 類型:
<number>|<undefined>
相對於 rl.line 的游標位置。
當從 TTY 串流讀取輸入時,這將追蹤目前游標在輸入字串中的位置。游標的位置決定了輸入字串中隨著輸入處理而修改的部分,以及終端機插入符號 (caret) 的渲染欄位。
rl.getCursorPos()#
回傳游標相對於輸入提示 + 字串的實際位置。計算中包含長輸入(換行)字串以及多行提示。
Promises API#
類別:readlinePromises.Interface#
readlinePromises.Interface 類別的執行個體是使用 readlinePromises.createInterface() 方法建構的。每個執行個體都與單個 input 可讀取 串流和單個 output 可寫入 串流相關聯。output 串流用於為 input 串流上抵達並讀取的輸入列印提示訊息。
rl.question(query[, options])#
query<string>要寫入output的陳述或問題,會加在提示字串之前。options<Object>signal<AbortSignal>選擇性地允許使用AbortSignal取消question()。
- 回傳:
<Promise>一個 Promise,其履行值為使用者對query的輸入回應。
rl.question() 方法透過將 query 寫入 output 來顯示問題,等待使用者在 input 上提供輸入,然後調用 callback 函式並將提供的輸入作為第一個參數傳遞。
呼叫時,如果 input 串流已暫停,rl.question() 會將其恢復。
如果建立 readlinePromises.Interface 時將 output 設定為 null 或 undefined,則不會寫入 query。
如果在 rl.close() 之後呼叫問題,它會回傳一個被拒絕 (rejected) 的 promise。
使用範例
const answer = await rl.question('What is your favorite food? ');
console.log(`Oh, so your favorite food is ${answer}`);
使用 AbortSignal 取消問題。
const signal = AbortSignal.timeout(10_000);
signal.addEventListener('abort', () => {
console.log('The food question timed out');
}, { once: true });
const answer = await rl.question('What is your favorite food? ', { signal });
console.log(`Oh, so your favorite food is ${answer}`);
類別:readlinePromises.Readline#
new readlinePromises.Readline(stream[, options])#
stream<stream.Writable>一個 TTY 串流。options<Object>autoCommit<boolean>如果為true,則無需呼叫rl.commit()。
rl.clearLine(dir)#
dir<integer>-1:游標以左1:游標以右0:整行
- 回傳:this
rl.clearLine() 方法會將清除相關 stream 目前行(由 dir 指定方向)的動作加入內部待處理動作列表中。除非在建構子中傳遞了 autoCommit: true,否則需呼叫 rl.commit() 才能看到此方法的成效。
rl.clearScreenDown()#
- 回傳:this
rl.clearScreenDown() 方法會將清除相關串流目前游標位置以下內容的動作加入內部待處理動作列表中。除非在建構子中傳遞了 autoCommit: true,否則需呼叫 rl.commit() 才能看到此方法的成效。
rl.commit()#
- 傳回:
<Promise>
rl.commit() 方法將所有待處理動作傳送到相關的 stream 並清除內部待處理動作列表。
rl.cursorTo(x[, y])#
rl.cursorTo() 方法會將移動游標到相關 stream 中指定位置的動作加入內部待處理動作列表中。除非在建構子中傳遞了 autoCommit: true,否則需呼叫 rl.commit() 才能看到此方法的成效。
rl.moveCursor(dx, dy)#
rl.moveCursor() 方法會將相對於相關 stream 中目前位置移動游標的動作加入內部待處理動作列表中。除非在建構子中傳遞了 autoCommit: true,否則需呼叫 rl.commit() 才能看到此方法的成效。
rl.rollback()#
- 回傳:this
rl.rollback 方法會清除內部待處理動作列表,而不將其傳送到相關的 stream。
readlinePromises.createInterface(options)#
options<Object>input<stream.Readable>要監聽的 可讀取 串流。此選項為必填。output<stream.Writable>用於寫入 readline 資料的 可寫入 串流。completer<Function>用於 Tab 自動補全的可選函式。terminal<boolean>如果input和output串流應被視為 TTY,並向其寫入 ANSI/VT100 轉義碼,則為true。預設值: 實例化時檢查output串流的isTTY。history<string[]>歷史紀錄行的初始列表。僅當使用者或內部output檢查將terminal設定為true時,此選項才有意義,否則完全不會初始化歷史快取機制。預設值:[]。historySize<number>保留的歷史紀錄行數上限。要停用歷史紀錄,請將此值設定為0。僅當使用者或內部output檢查將terminal設定為true時,此選項才有意義,否則完全不會初始化歷史快取機制。預設值:30。removeHistoryDuplicates<boolean>如果為true,當加入歷史列表的新輸入行與舊行重複時,將從列表中移除舊行。預設值:false。prompt<string>要使用的提示字串。預設值:'> '。crlfDelay<number>如果\r和\n之間的延遲超過crlfDelay毫秒,則\r和\n都將被視為單獨的行尾輸入。crlfDelay將被強制轉換為不小於100的數字。它可以設定為Infinity,在這種情況下,\r後接\n將始終被視為單個換行符(這對於使用\r\n行分隔符讀取檔案可能是合理的)。預設值:100。escapeCodeTimeout<number>readlinePromises等待一個字元的時間(以毫秒為單位,用於讀取歧義按鍵序列——即既可以根據到目前為止讀取的輸入形成完整的按鍵序列,又可以接收額外輸入來完成更長按鍵序列的情況)。預設值:500。tabSize<integer>一個 tab 等於的空格數(最小為 1)。預設值:8。signal<AbortSignal>允許使用 AbortSignal 關閉介面。
- 回傳:
<readlinePromises.Interface>
readlinePromises.createInterface() 方法建立一個新的 readlinePromises.Interface 執行個體。
import { createInterface } from 'node:readline/promises'; import { stdin, stdout } from 'node:process'; const rl = createInterface({ input: stdin, output: stdout, });const { createInterface } = require('node:readline/promises'); const rl = createInterface({ input: process.stdin, output: process.stdout, });
一旦建立了 readlinePromises.Interface 執行個體,最常見的情況是監聽 'line' 事件:
rl.on('line', (line) => {
console.log(`Received: ${line}`);
});
如果此執行個體的 terminal 為 true,則 output 串流若定義了 output.columns 屬性,並且在欄數發生變化時觸發 'resize' 事件,則會獲得最佳相容性(當 process.stdout 為 TTY 時會自動執行此操作)。
completer 函式的使用#
completer 函式將使用者輸入的目前行作為參數,並回傳一個包含 2 個項目的 Array:
- 一個包含補全匹配項的
Array。 - 用於匹配的子字串。
例如:[[substr1, substr2, ...], originalsubstring]。
function completer(line) {
const completions = '.help .error .exit .quit .q'.split(' ');
const hits = completions.filter((c) => c.startsWith(line));
// Show all completions if none found
return [hits.length ? hits : completions, line];
}
completer 函式也可以回傳一個 <Promise>,或者是同步的:
async function completer(linePartial) {
await someAsyncWork();
return [['123'], linePartial];
}
Callback API#
類別:readline.Interface#
readline.Interface 類別的執行個體是使用 readline.createInterface() 方法建構的。每個執行個體都與單個 input 可讀取 串流和單個 output 可寫入 串流相關聯。output 串流用於為 input 串流上抵達並讀取的輸入列印提示訊息。
rl.question(query[, options], callback)#
query<string>要寫入output的陳述或問題,會加在提示字串之前。options<Object>signal<AbortSignal>選擇性地允許使用AbortController取消question()。
callback<Function>一個回呼函式,其調用時會傳入使用者對query的輸入回應。
rl.question() 方法透過將 query 寫入 output 來顯示問題,等待使用者在 input 上提供輸入,然後調用 callback 函式並將提供的輸入作為第一個參數傳遞。
呼叫時,如果 input 串流已暫停,rl.question() 會將其恢復。
如果建立 readline.Interface 時將 output 設定為 null 或 undefined,則不會寫入 query。
傳遞給 rl.question() 的 callback 函式不遵循接受 Error 物件或 null 作為第一個參數的典型模式。callback 被呼叫時,提供的答案是唯一的參數。
如果在 rl.close() 之後呼叫 rl.question(),將拋出錯誤。
使用範例
rl.question('What is your favorite food? ', (answer) => {
console.log(`Oh, so your favorite food is ${answer}`);
});
使用 AbortController 取消問題。
const ac = new AbortController();
const signal = ac.signal;
rl.question('What is your favorite food? ', { signal }, (answer) => {
console.log(`Oh, so your favorite food is ${answer}`);
});
signal.addEventListener('abort', () => {
console.log('The food question timed out');
}, { once: true });
setTimeout(() => ac.abort(), 10000);
readline.clearLine(stream, dir[, callback])#
stream<stream.Writable>dir<number>-1:游標以左1:游標以右0:整行
callback<Function>操作完成後調用。- 回傳:
<boolean>如果stream希望呼叫程式碼在繼續寫入額外資料之前等待'drain'事件觸發,則為false;否則為true。
readline.clearLine() 方法會清除指定 TTY 串流中由 dir 識別的特定方向的目前行。
readline.clearScreenDown(stream[, callback])#
stream<stream.Writable>callback<Function>操作完成後調用。- 回傳:
<boolean>如果stream希望呼叫程式碼在繼續寫入額外資料之前等待'drain'事件觸發,則為false;否則為true。
readline.clearScreenDown() 方法會清除指定 TTY 串流中目前游標位置以下的所有內容。
readline.createInterface(options)#
options<Object>input<stream.Readable>要監聽的 可讀取 串流。此選項為必填。output<stream.Writable>用於寫入 readline 資料的 可寫入 串流。completer<Function>用於 Tab 自動補全的可選函式。terminal<boolean>如果input和output串流應被視為 TTY,並向其寫入 ANSI/VT100 轉義碼,則為true。預設值: 實例化時檢查output串流的isTTY。history<string[]>歷史紀錄行的初始列表。僅當使用者或內部output檢查將terminal設定為true時,此選項才有意義,否則完全不會初始化歷史快取機制。預設值:[]。historySize<number>保留的歷史紀錄行數上限。要停用歷史紀錄,請將此值設定為0。僅當使用者或內部output檢查將terminal設定為true時,此選項才有意義,否則完全不會初始化歷史快取機制。預設值:30。removeHistoryDuplicates<boolean>如果為true,當加入歷史列表的新輸入行與舊行重複時,將從列表中移除舊行。預設值:false。prompt<string>要使用的提示字串。預設值:'> '。crlfDelay<number>如果\r和\n之間的延遲超過crlfDelay毫秒,則\r和\n都將被視為單獨的行尾輸入。crlfDelay將被強制轉換為不小於100的數字。它可以設定為Infinity,在這種情況下,\r後接\n將始終被視為單個換行符(這對於使用\r\n行分隔符讀取檔案可能是合理的)。預設值:100。escapeCodeTimeout<number>readline等待一個字元的時間(以毫秒為單位,用於讀取歧義按鍵序列——即既可以根據到目前為止讀取的輸入形成完整的按鍵序列,又可以接收額外輸入來完成更長按鍵序列的情況)。預設值:500。tabSize<integer>一個 tab 等於的空格數(最小為 1)。預設值:8。signal<AbortSignal>允許使用 AbortSignal 關閉介面。中止信號將在內部對介面呼叫close。
- 回傳:
<readline.Interface>
readline.createInterface() 方法建立一個新的 readline.Interface 執行個體。
import { createInterface } from 'node:readline'; import { stdin, stdout } from 'node:process'; const rl = createInterface({ input: stdin, output: stdout, });const { createInterface } = require('node:readline'); const rl = createInterface({ input: process.stdin, output: process.stdout, });
一旦建立了 readline.Interface 執行個體,最常見的情況是監聽 'line' 事件:
rl.on('line', (line) => {
console.log(`Received: ${line}`);
});
如果此執行個體的 terminal 為 true,則 output 串流若定義了 output.columns 屬性,並且在欄數發生變化時觸發 'resize' 事件,則會獲得最佳相容性(當 process.stdout 為 TTY 時會自動執行此操作)。
當使用 stdin 作為輸入建立 readline.Interface 時,程式不會終止,直到收到 EOF 字元。要在不等待使用者輸入的情況下退出,請呼叫 process.stdin.unref()。
completer 函式的使用#
completer 函式將使用者輸入的目前行作為參數,並回傳一個包含 2 個項目的 Array:
- 一個包含補全匹配項的
Array。 - 用於匹配的子字串。
例如:[[substr1, substr2, ...], originalsubstring]。
function completer(line) {
const completions = '.help .error .exit .quit .q'.split(' ');
const hits = completions.filter((c) => c.startsWith(line));
// Show all completions if none found
return [hits.length ? hits : completions, line];
}
如果 completer 函式接受兩個參數,則可以非同步呼叫:
function completer(linePartial, callback) {
callback(null, [['123'], linePartial]);
}
readline.cursorTo(stream, x[, y][, callback])#
stream<stream.Writable>x<number>y<number>callback<Function>操作完成後調用。- 回傳:
<boolean>如果stream希望呼叫程式碼在繼續寫入額外資料之前等待'drain'事件觸發,則為false;否則為true。
readline.cursorTo() 方法將游標移動到指定 TTY stream 中的指定位置。
readline.moveCursor(stream, dx, dy[, callback])#
stream<stream.Writable>dx<number>dy<number>callback<Function>操作完成後調用。- 回傳:
<boolean>如果stream希望呼叫程式碼在繼續寫入額外資料之前等待'drain'事件觸發,則為false;否則為true。
readline.moveCursor() 方法會將游標相對於其在指定 TTY stream 中的目前位置進行移動。
readline.emitKeypressEvents(stream[, interface])#
stream<stream.Readable>interface<readline.InterfaceConstructor>
readline.emitKeypressEvents() 方法使指定的 可讀取 串流開始觸發與接收到的輸入相對應的 'keypress' 事件。
選擇性地,interface 指定一個 readline.Interface 執行個體,當偵測到複製貼上的輸入時,會為其停用自動補全。
如果 stream 是一個 TTY,則它必須處於 raw 模式。
如果輸入是終端機,任何 readline 執行個體都會對其 input 自動呼叫此方法。關閉 readline 執行個體不會停止 input 觸發 'keypress' 事件。
readline.emitKeypressEvents(process.stdin);
if (process.stdin.isTTY)
process.stdin.setRawMode(true);
範例:微型 CLI#
以下範例說明了使用 readline.Interface 類別來實作一個小型命令列介面:
import { createInterface } from 'node:readline'; import { exit, stdin, stdout } from 'node:process'; const rl = createInterface({ input: stdin, output: stdout, prompt: 'OHAI> ', }); rl.prompt(); rl.on('line', (line) => { switch (line.trim()) { case 'hello': console.log('world!'); break; default: console.log(`Say what? I might have heard '${line.trim()}'`); break; } rl.prompt(); }).on('close', () => { console.log('Have a great day!'); exit(0); });const { createInterface } = require('node:readline'); const rl = createInterface({ input: process.stdin, output: process.stdout, prompt: 'OHAI> ', }); rl.prompt(); rl.on('line', (line) => { switch (line.trim()) { case 'hello': console.log('world!'); break; default: console.log(`Say what? I might have heard '${line.trim()}'`); break; } rl.prompt(); }).on('close', () => { console.log('Have a great day!'); process.exit(0); });
範例:逐行讀取檔案串流#
readline 的一個常見用例是逐行消耗輸入檔案。最簡單的方法是利用 fs.ReadStream API 以及 for await...of 迴圈:
import { createReadStream } from 'node:fs'; import { createInterface } from 'node:readline'; async function processLineByLine() { const fileStream = createReadStream('input.txt'); const rl = createInterface({ input: fileStream, crlfDelay: Infinity, }); // Note: we use the crlfDelay option to recognize all instances of CR LF // ('\r\n') in input.txt as a single line break. for await (const line of rl) { // Each line in input.txt will be successively available here as `line`. console.log(`Line from file: ${line}`); } } processLineByLine();const { createReadStream } = require('node:fs'); const { createInterface } = require('node:readline'); async function processLineByLine() { const fileStream = createReadStream('input.txt'); const rl = createInterface({ input: fileStream, crlfDelay: Infinity, }); // Note: we use the crlfDelay option to recognize all instances of CR LF // ('\r\n') in input.txt as a single line break. for await (const line of rl) { // Each line in input.txt will be successively available here as `line`. console.log(`Line from file: ${line}`); } } processLineByLine();
或者,也可以使用 'line' 事件:
import { createReadStream } from 'node:fs'; import { createInterface } from 'node:readline'; const rl = createInterface({ input: createReadStream('sample.txt'), crlfDelay: Infinity, }); rl.on('line', (line) => { console.log(`Line from file: ${line}`); });const { createReadStream } = require('node:fs'); const { createInterface } = require('node:readline'); const rl = createInterface({ input: createReadStream('sample.txt'), crlfDelay: Infinity, }); rl.on('line', (line) => { console.log(`Line from file: ${line}`); });
目前,for await...of 迴圈可能會稍微慢一些。如果 async / await 流程和速度都很重要,可以採用混合方法:
import { once } from 'node:events'; import { createReadStream } from 'node:fs'; import { createInterface } from 'node:readline'; (async function processLineByLine() { try { const rl = createInterface({ input: createReadStream('big-file.txt'), crlfDelay: Infinity, }); rl.on('line', (line) => { // Process the line. }); await once(rl, 'close'); console.log('File processed.'); } catch (err) { console.error(err); } })();const { once } = require('node:events'); const { createReadStream } = require('node:fs'); const { createInterface } = require('node:readline'); (async function processLineByLine() { try { const rl = createInterface({ input: createReadStream('big-file.txt'), crlfDelay: Infinity, }); rl.on('line', (line) => { // Process the line. }); await once(rl, 'close'); console.log('File processed.'); } catch (err) { console.error(err); } })();
TTY 快捷鍵#
| 快捷鍵 (Keybindings) | 說明 | 備註 |
|---|---|---|
| Ctrl+Shift+Backspace | 刪除游標左側整行 | 在 Linux、Mac 和 Windows 上無效 |
| Ctrl+Shift+Delete | 刪除游標右側整行 | 在 Mac 上無效 |
| Ctrl+C | 觸發 SIGINT 或關閉 readline 執行個體 |
|
| Ctrl+H | 向左刪除 | |
| Ctrl+D | 向右刪除,或在目前行為空 / EOF 的情況下關閉 readline 執行個體 | 在 Windows 上無效 |
| Ctrl+U | 從目前位置刪除至行首 | |
| Ctrl+K | 從目前位置刪除至行尾 | |
| Ctrl+Y | 貼上(召回)先前刪除的文字 | 僅適用於由 Ctrl+U 或 Ctrl+K 刪除的文字 |
| Meta+Y | 在先前刪除的文字之間循環切換 | 僅當最後一次按鍵是 Ctrl+Y 或 Meta+Y 時可用 |
| Ctrl+A | 移至行首 | |
| Ctrl+E | 移至行尾 | |
| Ctrl+B | 向後移一個字元 | |
| Ctrl+F | 向前移一個字元 | |
| Ctrl+L | 清除螢幕 | |
| Ctrl+N | 下一個歷史項目 | |
| Ctrl+P | 上一個歷史項目 | |
| Ctrl+- | 復原上一次更改 | 任何觸發鍵代碼 0x1F 的按鍵動作都會執行此動作。在許多終端機(例如 xterm)中,這被綁定到 Ctrl+-。 |
| Ctrl+6 | 重做上一次更改 | 許多終端機沒有預設的重做按鍵。我們選擇鍵代碼 0x1E 來執行重做。在 xterm 中,預設綁定到 Ctrl+6。 |
| Ctrl+Z | 將執行中程序移至背景。輸入 fg 並按 Enter 即可返回。 |
在 Windows 上無效 |
| Ctrl+W 或 Ctrl +Backspace | 向後刪除至單字邊界 | Ctrl+Backspace 在 Linux、Mac 和 Windows 上無效 |
| Ctrl+Delete | 向前刪除至單字邊界 | 在 Mac 上無效 |
| Ctrl+Left arrow 或 Meta+B | 向左一個單字 | Ctrl+Left arrow 在 Mac 上無效 |
| Ctrl+Right arrow 或 Meta+F | 向右一個單字 | Ctrl+Right arrow 在 Mac 上無效 |
| Meta+D 或 Meta +Delete | 向右刪除單字 | Meta+Delete 在 Windows 上無效 |
| Meta+Backspace | 向左刪除單字 | 在 Mac 上無效 |