Node.js v26.0.0 說明文件
- Node.js v26.0.0
- 目錄
- 索引
- 關於此說明文件
- 用法與範例
- 斷言測試
- 非同步內容追蹤
- 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 可反覆運算壓縮
- 其他版本
- 選項
REPL#
穩定度:2 - 穩定
node:repl 模組提供了「讀取-評估-列印-迴圈」(Read-Eval-Print-Loop, REPL) 的實作,既可作為獨立程式使用,也可嵌入其他應用程式中。可以透過以下方式存取:
import repl from 'node:repl';const repl = require('node:repl');
設計與功能#
node:repl 模組導出了 repl.REPLServer 類別。在執行期間,repl.REPLServer 的實例會接收使用者輸入的每一行程式碼,根據使用者定義的評估函式進行評估,然後輸出結果。輸入與輸出可以分別來自 stdin 和 stdout,也可以連接到任何 Node.js 串流 (stream)。
repl.REPLServer 的實例支援輸入自動完成、完成預覽、簡易的 Emacs 風格行編輯、多行輸入、類似 ZSH 的反向搜尋 (reverse-i-search)、類似 ZSH 的子字串歷史紀錄搜尋、ANSI 風格輸出、儲存與恢復當前 REPL 工作階段狀態、錯誤恢復以及自定義評估函式。不支援 ANSI 風格和 Emacs 風格行編輯的終端機將自動切換為有限的功能集。
指令與特殊按鍵#
所有 REPL 實例均支援以下特殊指令:
.break:當輸入多行表達式時,輸入.break指令(或按 Ctrl+C)可中止該表達式的進一步輸入或處理。.clear:將 REPL 的context重設為空物件,並清除正在輸入的任何多行表達式。.exit:關閉 I/O 串流,導致 REPL 結束。.help:顯示特殊指令列表。.save:將當前 REPL 工作階段儲存至檔案:> .save ./file/to/save.js.load:將檔案載入至當前 REPL 工作階段。> .load ./file/to/load.js.editor:進入編輯器模式(按 Ctrl+D 完成,按 Ctrl+C 取消)。
> .editor
// Entering editor mode (^D to finish, ^C to cancel)
function welcome(name) {
return `Hello ${name}!`;
}
welcome('Node.js User');
// ^D
'Hello Node.js User!'
>
REPL 中的以下按鍵組合具有特殊效果:
- Ctrl+C:按一次時,效果與
.break指令相同。在空白行連續按兩次時,效果與.exit指令相同。 - Ctrl+D:效果與
.exit指令相同。 - Tab:在空白行按下時,顯示全域與區域(範疇)變數。在輸入內容時按下時,顯示相關的自動完成選項。
有關反向搜尋的按鍵綁定,請參閱 reverse-i-search。對於所有其他按鍵綁定,請參閱 TTY 按鍵綁定。
預設評估#
預設情況下,所有 repl.REPLServer 實例皆使用一個評估函式,該函式會評估 JavaScript 表達式並提供對 Node.js 內建模組的存取。此預設行為可以透過在建立 repl.REPLServer 實例時傳入替代的評估函式來覆寫。
JavaScript 表達式#
預設的評估器支援對 JavaScript 表達式的直接評估。
> 1 + 1
2
> const m = 2
undefined
> m + 1
3
除非在區塊或函式內有其他範圍限制,否則隱式宣告或使用 const、let 或 var 關鍵字宣告的變數皆屬於全域範疇。
全域與區域範疇#
預設評估器提供對全域範疇內存在的任何變數的存取權。可以透過將變數指派給與每個 REPLServer 相關聯的 context 物件,來明確地將變數暴露給 REPL。
import repl from 'node:repl'; const msg = 'message'; repl.start('> ').context.m = msg;const repl = require('node:repl'); const msg = 'message'; repl.start('> ').context.m = msg;
context 物件中的屬性在 REPL 中表現為區域變數。
$ node repl_test.js
> m
'message'
Context 屬性預設並非唯讀。若要指定唯讀的全域變數,必須使用 Object.defineProperty() 定義 context 屬性。
import repl from 'node:repl'; const msg = 'message'; const r = repl.start('> '); Object.defineProperty(r.context, 'm', { configurable: false, enumerable: true, value: msg, });const repl = require('node:repl'); const msg = 'message'; const r = repl.start('> '); Object.defineProperty(r.context, 'm', { configurable: false, enumerable: true, value: msg, });
存取核心 Node.js 模組#
預設評估器會在 Node.js 核心模組被使用時,自動將其載入至 REPL 環境中。例如,除非宣告為全域或區域變數,否則輸入 fs 將會按需評估為 global.fs = require('node:fs')。
> fs.createReadStream('./some/file');
全域未捕獲例外#
REPL 使用 domain 模組來捕獲該 REPL 工作階段中的所有未捕獲例外。
在 REPL 中使用 domain 模組會產生以下副作用:
-
未捕獲例外僅在獨立 REPL 中才會發出
'uncaughtException'事件。在另一個 Node.js 程式內的 REPL 中為此事件新增監聽器將導致ERR_INVALID_REPL_INPUT。const r = repl.start(); r.write('process.on("uncaughtException", () => console.log("Foobar"));\n'); // Output stream includes: // TypeError [ERR_INVALID_REPL_INPUT]: Listeners for `uncaughtException` // cannot be used in the REPL r.close(); -
嘗試使用
process.setUncaughtExceptionCaptureCallback()會拋出ERR_DOMAIN_CANNOT_SET_UNCAUGHT_EXCEPTION_CAPTURE錯誤。
_ (底線) 變數的賦值#
預設情況下,預設評估器會將最近評估的表達式結果指派給特殊變數 _(底線)。明確地將 _ 設為某個值將停用此行為。
> [ 'a', 'b', 'c' ]
[ 'a', 'b', 'c' ]
> _.length
3
> _ += 1
Expression assignment to _ now disabled.
4
> 1 + 1
2
> _
4
類似地,若有發生錯誤,_error 將參考最後一次出現的錯誤。明確地將 _error 設為某個值將停用此行為。
> throw new Error('foo');
Uncaught Error: foo
> _error.message
'foo'
await 關鍵字#
已在最上層啟用對 await 關鍵字的支援。
> await Promise.resolve(123)
123
> await Promise.reject(new Error('REPL await'))
Uncaught Error: REPL await
at REPL2:1:54
> const timeout = util.promisify(setTimeout);
undefined
> const old = Date.now(); await timeout(1000); console.log(Date.now() - old);
1002
undefined
在 REPL 中使用 await 關鍵字的一個已知限制是,它會使 const 關鍵字的語法範疇無效。
例如:
> const m = await Promise.resolve(123)
undefined
> m
123
> m = await Promise.resolve(234)
234
// redeclaring the constant does error
> const m = await Promise.resolve(345)
Uncaught SyntaxError: Identifier 'm' has already been declared
--no-experimental-repl-await 將會停用 REPL 中的最上層 await。
反向搜尋 (Reverse-i-search)#
REPL 支援類似 ZSH 的雙向反向搜尋。透過 Ctrl+R 向後搜尋,透過 Ctrl+S 向前搜尋。
重複的歷史紀錄項目將會被略過。
一旦按下不屬於反向搜尋的任何按鍵,即會接受當前項目。按下 Esc 或 Ctrl+C 可取消。
改變方向會立即從當前位置開始,搜尋預期方向上的下一個項目。
自定義評估函式#
當建立新的 repl.REPLServer 時,可以提供自定義的評估函式。這可以用於實作完全客製化的 REPL 應用程式。
評估函式接收以下四個參數:
code<string>要執行的程式碼(例如1 + 1)。context<Object>執行程式碼的內容環境。根據useGlobal選項,這可以是 JavaScript 的global環境或 REPL 實例特有的環境。replResourceName<string>與當前程式碼評估相關聯的 REPL 資源識別碼。這對於除錯很有用。callback<Function>程式碼評估完成後呼叫的函式。回呼函式接收兩個參數:- 若評估期間發生錯誤,則提供錯誤物件;若未發生錯誤,則提供
null或undefined。 - 程式碼評估的結果(若有提供錯誤,此參數無關緊要)。
- 若評估期間發生錯誤,則提供錯誤物件;若未發生錯誤,則提供
以下範例展示了一個將給定數字平方的 REPL,若輸入的不是數字,則會列印出錯誤訊息。
import repl from 'node:repl'; function byThePowerOfTwo(number) { return number * number; } function myEval(code, context, replResourceName, callback) { if (isNaN(code)) { callback(new Error(`${code.trim()} is not a number`)); } else { callback(null, byThePowerOfTwo(code)); } } repl.start({ prompt: 'Enter a number: ', eval: myEval });const repl = require('node:repl'); function byThePowerOfTwo(number) { return number * number; } function myEval(code, context, replResourceName, callback) { if (isNaN(code)) { callback(new Error(`${code.trim()} is not a number`)); } else { callback(null, byThePowerOfTwo(code)); } } repl.start({ prompt: 'Enter a number: ', eval: myEval });
可恢復的錯誤#
在 REPL 提示符下,按下 Enter 會將當前輸入行傳送至 eval 函式。為了支援多行輸入,eval 函式可以向提供的回呼函式回傳一個 repl.Recoverable 實例。
function myEval(cmd, context, filename, callback) {
let result;
try {
result = vm.runInThisContext(cmd);
} catch (e) {
if (isRecoverableError(e)) {
return callback(new repl.Recoverable(e));
}
}
callback(null, result);
}
function isRecoverableError(error) {
if (error.name === 'SyntaxError') {
return /^(Unexpected end of input|Unexpected token)/.test(error.message);
}
return false;
}
自定義 REPL 輸出#
預設情況下,repl.REPLServer 實例在將輸出寫入提供的 Writable 串流(預設為 process.stdout)之前,會使用 util.inspect() 方法格式化輸出。showProxy 檢查選項預設為 true,且 colors 選項會根據 REPL 的 useColors 選項決定是否為 true。
可以在建構時指定 useColors 布林選項,指示預設寫入器使用 ANSI 風格代碼來為 util.inspect() 方法的輸出上色。
如果 REPL 作為獨立程式執行,也可以在 REPL 內部透過 inspect.replDefaults 屬性變更 REPL 的 檢查預設值,該屬性對應於 util.inspect() 中的 defaultOptions。
> util.inspect.replDefaults.compact = false;
false
> [1]
[
1
]
>
若要完全自定義 repl.REPLServer 實例的輸出,請在建構時為 writer 選項傳入一個新函式。例如,以下範例會將任何輸入文字轉換為大寫:
import repl from 'node:repl'; const r = repl.start({ prompt: '> ', eval: myEval, writer: myWriter }); function myEval(cmd, context, filename, callback) { callback(null, cmd); } function myWriter(output) { return output.toUpperCase(); }const repl = require('node:repl'); const r = repl.start({ prompt: '> ', eval: myEval, writer: myWriter }); function myEval(cmd, context, filename, callback) { callback(null, cmd); } function myWriter(output) { return output.toUpperCase(); }
類別:REPLServer#
options<Object>|<string>請參閱repl.start()- 繼承自:
<readline.Interface>
repl.REPLServer 的實例是使用 repl.start() 方法或直接使用 JavaScript new 關鍵字建立的。
import repl from 'node:repl'; const options = { useColors: true }; const firstInstance = repl.start(options); const secondInstance = new repl.REPLServer(options);const repl = require('node:repl'); const options = { useColors: true }; const firstInstance = repl.start(options); const secondInstance = new repl.REPLServer(options);
事件:'exit'#
當 REPL 因收到 .exit 指令、使用者連續兩次按 Ctrl+C 發送 SIGINT,或是按下 Ctrl+D 於輸入串流發送 'end' 而結束時,會發出 'exit' 事件。監聽器的回呼函式不帶任何參數被呼叫。
replServer.on('exit', () => {
console.log('Received "exit" event from repl!');
process.exit();
});
事件:'reset'#
當 REPL 的內容環境 (context) 重設時,會發出 'reset' 事件。這發生在收到 .clear 指令時,除非 REPL 使用預設評估器且 repl.REPLServer 實例在建立時將 useGlobal 選項設為 true。監聽器的回呼函式將會以 context 物件的參考作為唯一參數進行呼叫。
這主要用於將 REPL 環境重初始化為某種預定義狀態。
import repl from 'node:repl'; function initializeContext(context) { context.m = 'test'; } const r = repl.start({ prompt: '> ' }); initializeContext(r.context); r.on('reset', initializeContext);const repl = require('node:repl'); function initializeContext(context) { context.m = 'test'; } const r = repl.start({ prompt: '> ' }); initializeContext(r.context); r.on('reset', initializeContext);
執行此程式碼時,可以修改全域 'm' 變數,但隨後可以使用 .clear 指令將其重設為初始值。
$ ./node example.js
> m
'test'
> m = 1
1
> m
1
> .clear
Clearing context...
> m
'test'
>
replServer.defineCommand(keyword, cmd)#
keyword<string>指令關鍵字(不含前導的.字元)。cmd<Object>|<Function>處理指令時呼叫的函式。
replServer.defineCommand() 方法用於將新的以 . 開頭的指令新增至 REPL 實例。此類指令透過輸入 . 後接 keyword 來呼叫。cmd 可以是一個 Function 或是一個具有以下屬性的 Object:
help<string>輸入.help時顯示的說明文字(選填)。action<Function>要執行的函式,可選擇性地接收單個字串參數。
以下範例展示了兩個新增至 REPL 實例的新指令:
import repl from 'node:repl'; const replServer = repl.start({ prompt: '> ' }); replServer.defineCommand('sayhello', { help: 'Say hello', action(name) { this.clearBufferedCommand(); console.log(`Hello, ${name}!`); this.displayPrompt(); }, }); replServer.defineCommand('saybye', function saybye() { console.log('Goodbye!'); this.close(); });const repl = require('node:repl'); const replServer = repl.start({ prompt: '> ' }); replServer.defineCommand('sayhello', { help: 'Say hello', action(name) { this.clearBufferedCommand(); console.log(`Hello, ${name}!`); this.displayPrompt(); }, }); replServer.defineCommand('saybye', function saybye() { console.log('Goodbye!'); this.close(); });
接著可以在 REPL 實例中使用這些新指令:
> .sayhello Node.js User
Hello, Node.js User!
> .saybye
Goodbye!
replServer.displayPrompt([preserveCursor])#
preserveCursor<boolean>
replServer.displayPrompt() 方法準備 REPL 實例以接收使用者輸入,在 output 中列印已配置的 prompt 到新的一行,並恢復 input 以接收新的輸入。
當輸入多行內容時,會列印管道符號 '|' 而非 'prompt'。
當 preserveCursor 為 true 時,游標位置將不會重設為 0。
replServer.displayPrompt 方法主要用於在使用 replServer.defineCommand() 方法註冊的指令的 action 函式內呼叫。
replServer.clearBufferedCommand()#
replServer.clearBufferedCommand() 方法會清除任何已緩衝但尚未執行的指令。此方法主要用於在使用 replServer.defineCommand() 方法註冊的指令的 action 函式內呼叫。
replServer.setupHistory(historyConfig, callback)#
historyConfig<Object>|<string>歷史紀錄檔案路徑。如果是字串,則是歷史紀錄檔案的路徑。如果是物件,可以包含以下屬性:filePath<string>歷史紀錄檔案的路徑。size<number>保留的歷史紀錄最大行數。若要停用歷史紀錄,請將此值設為0。此選項僅在terminal被使用者或內部output檢查設為true時才有效,否則不會初始化歷史紀錄快取機制。預設值:30。removeHistoryDuplicates<boolean>如果為true,當加入歷史列表的新輸入行與舊行重複時,將從列表中移除舊行。預設值:false。onHistoryFileLoaded<Function>當歷史紀錄寫入就緒或發生錯誤時呼叫。err<Error>repl<repl.REPLServer>
callback<Function>當歷史紀錄寫入就緒或發生錯誤時呼叫(若已在historyConfig中提供onHistoryFileLoaded則為選填)。err<Error>repl<repl.REPLServer>
為 REPL 實例初始化歷史紀錄日誌檔案。當執行 Node.js 二進位檔並使用命令列 REPL 時,預設會初始化一個歷史紀錄檔案。然而,以程式方式建立 REPL 時並非如此。在以程式方式使用 REPL 實例時,請使用此方法來初始化歷史紀錄日誌檔案。
repl.builtinModules#
穩定性:0 - 已棄用。請改用 module.builtinModules。
- 類型:
<string[]>
部分 Node.js 模組名稱的列表,例如 'http'。
已有自動化遷移工具可用 (來源)
npx codemod@latest @nodejs/repl-builtin-modules
repl.start([options])#
options<Object>|<string>prompt<string>要顯示的輸入提示符。預設值:'> '(包含一個尾隨空格)。input<stream.Readable>讀取 REPL 輸入的Readable串流。預設值:process.stdin。output<stream.Writable>寫入 REPL 輸出的Writable串流。預設值:process.stdout。terminal<boolean>若為true,指定output應被視為 TTY 終端機。預設值: 實例化時檢查output串流上的isTTY屬性值。eval<Function>評估每一行輸入時使用的函式。預設值: JavaScripteval()函式的非同步封裝。eval函式若發生錯誤可傳回repl.Recoverable以指示輸入不完整,並提示輸入額外行數。詳細資訊請參閱自定義評估函式章節。useColors<boolean>若為true,指定預設writer函式應在 REPL 輸出中包含 ANSI 顏色樣式。若已提供自定義的writer函式,則此設定無效。預設值: 若 REPL 實例的terminal值為true,則檢查output串流的顏色支援。useGlobal<boolean>若為true,指定預設評估函式將使用 JavaScriptglobal作為環境,而不是為 REPL 實例建立新的獨立環境。Node CLI REPL 將此值設為true。預設值:false。ignoreUndefined<boolean>若為true,指定若指令評估結果為undefined,預設寫入器將不會輸出回傳值。預設值:false。writer<Function>在寫入output之前,用於格式化每個指令輸出的函式。預設值:util.inspect()。completer<Function>用於自定義 Tab 自動完成的可選函式。範例請參閱readline.InterfaceCompleter。replMode<symbol>指定預設評估器是否在嚴格模式或預設(鬆散)模式下執行所有 JavaScript 指令的旗標。可接受的值為:repl.REPL_MODE_SLOPPY:以鬆散模式評估表達式。repl.REPL_MODE_STRICT:以嚴格模式評估表達式。這等同於在每個 repl 語句前加上'use strict'。
breakEvalOnSigint<boolean>當收到SIGINT(例如按下 Ctrl+C)時,停止評估當前的程式碼片段。這不能與自定義eval函式一起使用。預設值:false。preview<boolean>定義 REPL 是否列印自動完成和輸出預覽。預設值: 在使用預設評估函式時為true,若使用自定義評估函式則為false。如果terminal為假值 (falsy),則不會有預覽,且preview的值無效。handleError<Function>此函式可自定義 REPL 中的錯誤處理。它將拋出的例外作為第一個參數接收,並必須同步回傳下列值之一:'print':將錯誤列印到輸出串流(預設行為)。'ignore':略過所有剩餘的錯誤處理。'unhandled':將例外視為完全未處理。在此情況下,錯誤將傳遞給行程範圍的例外處理器,例如'uncaughtException'事件。視具體使用場景而定,在REPLServer實例已關閉的情況下,'unhandled'值可能是也可能不是所需的行為。
- 回傳:
<repl.REPLServer>
repl.start() 方法會建立並啟動一個 repl.REPLServer 實例。
如果 options 為字串,則指定輸入提示符。
import repl from 'node:repl'; // a Unix style prompt repl.start('$ ');const repl = require('node:repl'); // a Unix style prompt repl.start('$ ');
Node.js REPL#
Node.js 本身使用 node:repl 模組來提供其專用的互動式 JavaScript 執行介面。這可以透過在不傳遞任何參數(或傳遞 -i 參數)的情況下執行 Node.js 二進位檔來使用。
$ node
> const a = [1, 2, 3];
undefined
> a
[ 1, 2, 3 ]
> a.forEach((v) => {
... console.log(v);
... });
1
2
3
環境變數選項#
Node.js REPL 的多種行為可以使用以下環境變數進行自定義:
NODE_REPL_HISTORY:當提供有效路徑時,持久化 REPL 歷史紀錄將儲存至該檔案,而非使用者家目錄下的.node_repl_history。將此值設為''(空字串)將停用持久化 REPL 歷史紀錄。值中的空白字元將被修剪。在 Windows 平台上,值為空內容的環境變數無效,因此若要停用,請將此變數設為一個或多個空格。NODE_REPL_HISTORY_SIZE:若啟用歷史紀錄,則控制保存的歷史行數。必須為正整數。預設值:1000。NODE_REPL_MODE:可以是'sloppy'或'strict'。預設值:'sloppy',這允許執行非嚴格模式的程式碼。
持久化歷史紀錄#
預設情況下,Node.js REPL 會透過將輸入儲存至位於使用者家目錄下的 .node_repl_history 檔案,來在不同的 node REPL 工作階段之間保留歷史紀錄。這可以透過設定環境變數 NODE_REPL_HISTORY='' 來停用。
在進階行編輯器中使用 Node.js REPL#
對於進階行編輯器,請使用環境變數 NODE_NO_READLINE=1 啟動 Node.js。這將以標準終端機設定啟動主 REPL 和除錯器 REPL,從而允許使用 rlwrap。
例如,可以在 .bashrc 檔案中新增以下內容:
alias node="env NODE_NO_READLINE=1 rlwrap node"
在同一個行程中啟動多個 REPL 實例#
可以在單個執行中的 Node.js 實例上建立並執行多個 REPL 實例,它們共用一個 global 物件(透過將 useGlobal 選項設為 true),但擁有獨立的 I/O 介面。
例如,以下範例在 stdin、Unix socket 和 TCP socket 上提供了獨立的 REPL,且它們都共用同一個 global 物件:
import net from 'node:net'; import repl from 'node:repl'; import process from 'node:process'; import fs from 'node:fs'; let connections = 0; repl.start({ prompt: 'Node.js via stdin> ', useGlobal: true, input: process.stdin, output: process.stdout, }); const unixSocketPath = '/tmp/node-repl-sock'; // If the socket file already exists let's remove it fs.rmSync(unixSocketPath, { force: true }); net.createServer((socket) => { connections += 1; repl.start({ prompt: 'Node.js via Unix socket> ', useGlobal: true, input: socket, output: socket, }).on('exit', () => { socket.end(); }); }).listen(unixSocketPath); net.createServer((socket) => { connections += 1; repl.start({ prompt: 'Node.js via TCP socket> ', useGlobal: true, input: socket, output: socket, }).on('exit', () => { socket.end(); }); }).listen(5001);const net = require('node:net'); const repl = require('node:repl'); const fs = require('node:fs'); let connections = 0; repl.start({ prompt: 'Node.js via stdin> ', useGlobal: true, input: process.stdin, output: process.stdout, }); const unixSocketPath = '/tmp/node-repl-sock'; // If the socket file already exists let's remove it fs.rmSync(unixSocketPath, { force: true }); net.createServer((socket) => { connections += 1; repl.start({ prompt: 'Node.js via Unix socket> ', useGlobal: true, input: socket, output: socket, }).on('exit', () => { socket.end(); }); }).listen(unixSocketPath); net.createServer((socket) => { connections += 1; repl.start({ prompt: 'Node.js via TCP socket> ', useGlobal: true, input: socket, output: socket, }).on('exit', () => { socket.end(); }); }).listen(5001);
從命令列執行此應用程式將啟動 stdin 上的 REPL。其他 REPL 用戶端可以透過 Unix socket 或 TCP socket 連接。例如,telnet 對於連接 TCP socket 非常有用,而 socat 則可用於連接 Unix 和 TCP socket。
透過從 Unix socket 伺服器而非 stdin 啟動 REPL,可以在不重新啟動的情況下連接到一個長時間執行的 Node.js 行程。
範例#
透過 net.Server 和 net.Socket 運作的全功能「終端」REPL#
這是一個展示如何使用 net.Server 和 net.Socket 執行「全功能」(終端)REPL 的範例:
以下腳本在連接埠 1337 上啟動一個 HTTP 伺服器,允許用戶端建立 socket 連接到其 REPL 實例。
// repl-server.js import repl from 'node:repl'; import net from 'node:net'; net .createServer((socket) => { const r = repl.start({ prompt: `socket ${socket.remoteAddress}:${socket.remotePort}> `, input: socket, output: socket, terminal: true, useGlobal: false, }); r.on('exit', () => { socket.end(); }); r.context.socket = socket; }) .listen(1337);// repl-server.js const repl = require('node:repl'); const net = require('node:net'); net .createServer((socket) => { const r = repl.start({ prompt: `socket ${socket.remoteAddress}:${socket.remotePort}> `, input: socket, output: socket, terminal: true, useGlobal: false, }); r.on('exit', () => { socket.end(); }); r.context.socket = socket; }) .listen(1337);
以下程式碼實作了一個可以透過連接埠 1337 與上述定義的伺服器建立 socket 連接的用戶端:
// repl-client.js import net from 'node:net'; import process from 'node:process'; const sock = net.connect(1337); process.stdin.pipe(sock); sock.pipe(process.stdout); sock.on('connect', () => { process.stdin.resume(); process.stdin.setRawMode(true); }); sock.on('close', () => { process.stdin.setRawMode(false); process.stdin.pause(); sock.removeListener('close', done); }); process.stdin.on('end', () => { sock.destroy(); console.log(); }); process.stdin.on('data', (b) => { if (b.length === 1 && b[0] === 4) { process.stdin.emit('end'); } });// repl-client.js const net = require('node:net'); const sock = net.connect(1337); process.stdin.pipe(sock); sock.pipe(process.stdout); sock.on('connect', () => { process.stdin.resume(); process.stdin.setRawMode(true); }); sock.on('close', () => { process.stdin.setRawMode(false); process.stdin.pause(); sock.removeListener('close', done); }); process.stdin.on('end', () => { sock.destroy(); console.log(); }); process.stdin.on('data', (b) => { if (b.length === 1 && b[0] === 4) { process.stdin.emit('end'); } });
若要執行此範例,請在機器上開啟兩個不同的終端機,在一個終端機中執行 node repl-server.js 啟動伺服器,在另一個終端機中執行 node repl-client.js。
透過 curl 使用的 REPL#
這是一個展示如何透過 curl() 執行 REPL 實例的範例:
以下腳本在連接埠 8000 上啟動一個 HTTP 伺服器,可以接受透過 curl() 建立的連接。
import http from 'node:http'; import repl from 'node:repl'; const server = http.createServer((req, res) => { res.setHeader('content-type', 'multipart/octet-stream'); repl.start({ prompt: 'curl repl> ', input: req, output: res, terminal: false, useColors: true, useGlobal: false, }); }); server.listen(8000);const http = require('node:http'); const repl = require('node:repl'); const server = http.createServer((req, res) => { res.setHeader('content-type', 'multipart/octet-stream'); repl.start({ prompt: 'curl repl> ', input: req, output: res, terminal: false, useColors: true, useGlobal: false, }); }); server.listen(8000);
當上述腳本執行時,您可以透過執行 curl --no-progress-meter -sSNT. localhost:8000 使用 curl() 連接至伺服器並進入其 REPL 實例。
警告:此範例純粹用於教育目的,旨在演示如何使用不同的 I/O 串流啟動 Node.js REPL。在生產環境或任何涉及安全性的情境中,若無額外的保護措施,請勿使用此範例。如果您需要在真實應用程式中實作 REPL,請考慮採取能減輕風險的替代方案,例如使用安全輸入機制並避免暴露網路介面。