柚子快報(bào)激活碼778899分享:Node.js---菜鳥(niǎo)教程
柚子快報(bào)激活碼778899分享:Node.js---菜鳥(niǎo)教程
文章目錄
創(chuàng)建第一個(gè)應(yīng)用創(chuàng)建 Node.js 應(yīng)用
NPM 使用介紹使用 npm 命令安裝模塊本地安裝使用 package.json模塊的操作
回調(diào)函數(shù)阻塞代碼實(shí)例非阻塞代碼
事件循環(huán)事件驅(qū)動(dòng)程序
EventEmitterEventEmitter 類(lèi)方法實(shí)例error 事件繼承 EventEmitter
Buffer(緩沖區(qū))Buffer 與字符編碼創(chuàng)建 Buffer 類(lèi)寫(xiě)入緩沖區(qū)從緩沖區(qū)讀取數(shù)據(jù)將 Buffer 轉(zhuǎn)換為 JSON 對(duì)象緩沖區(qū)合并緩沖區(qū)比較拷貝緩沖區(qū)緩沖區(qū)裁剪緩沖區(qū)長(zhǎng)度
Stream(流)從流中讀取數(shù)據(jù)寫(xiě)入流管道流鏈?zhǔn)搅?/p>
模塊系統(tǒng)引入模塊
函數(shù)匿名函數(shù)函數(shù)傳遞是如何讓 HTTP 服務(wù)器工作的
路由全局對(duì)象__filename__dirnamesetTimeout(cb, ms)clearTimeout(t)setInterval(cb, ms)consoleprocessProcess 屬性方法參考手冊(cè)
常用工具util.callbackifyutil.inheritsutil.inspectutil.isArrayutil.isRegExp(object)util.isDate(object)
文件系統(tǒng)異步和同步打開(kāi)文件獲取文件信息寫(xiě)入文件讀取文件關(guān)閉文件截取文件刪除文件創(chuàng)建目錄讀取目錄刪除目錄
GET/POST 請(qǐng)求獲取 GET 請(qǐng)求內(nèi)容獲取 POST 請(qǐng)求內(nèi)容
Web 模塊Web 應(yīng)用架構(gòu)使用 Node 創(chuàng)建 Web 服務(wù)器使用 Node 創(chuàng)建 Web 客戶(hù)端
Express 框架安裝第一個(gè) Express 框架實(shí)例請(qǐng)求和響應(yīng)路由靜態(tài)文件GET 方法POST 方法文件上傳Cookie 管理
RESTful API創(chuàng)建 RESTful獲取用戶(hù)列表:添加用戶(hù)顯示用戶(hù)詳情刪除用戶(hù)
多進(jìn)程exec() 方法
創(chuàng)建第一個(gè)應(yīng)用
讓我們先了解下 Node.js 應(yīng)用是由哪幾部分組成的:
require 指令:在 Node.js 中,使用 require 指令來(lái)加載和引入模塊,引入的模塊可以是內(nèi)置模塊,也可以是第三方模塊或自定義模塊。 創(chuàng)建服務(wù)器:服務(wù)器可以監(jiān)聽(tīng)客戶(hù)端的請(qǐng)求,類(lèi)似于 Apache 、Nginx 等 HTTP 服務(wù)器。 接收請(qǐng)求與響應(yīng)請(qǐng)求: 服務(wù)器很容易創(chuàng)建,客戶(hù)端可以使用瀏覽器或終端發(fā)送 HTTP 請(qǐng)求,服務(wù)器接收請(qǐng)求后返回響應(yīng)數(shù)據(jù)。
創(chuàng)建 Node.js 應(yīng)用
步驟一、使用 require 指令來(lái)加載和引入模塊
const module = require('module-name');
其中,module-name 可以是一個(gè)文件路徑(相對(duì)或絕對(duì)路徑),也可以是一個(gè)模塊名稱(chēng),如果是一個(gè)模塊名稱(chēng),Node.js 會(huì)自動(dòng)從 node_modules 目錄中查找該模塊。
我們使用 require 指令來(lái)載入 http 模塊,并將實(shí)例化的 HTTP 賦值給變量 http,實(shí)例如下:
var http = require("http");
步驟二、創(chuàng)建服務(wù)器 接下來(lái)我們使用 http.createServer() 方法創(chuàng)建服務(wù)器,并使用 listen 方法綁定 8888 端口。 函數(shù)通過(guò) request, response 參數(shù)來(lái)接收和響應(yīng)數(shù)據(jù)。
實(shí)例如下,在你項(xiàng)目的根目錄下創(chuàng)建一個(gè)叫 server.js 的文件,并寫(xiě)入以下代碼:
var http = require('http');
http.createServer(function (request, response) {
// 發(fā)送 HTTP 頭部
// HTTP 狀態(tài)值: 200 : OK
// 內(nèi)容類(lèi)型: text/plain
response.writeHead(200, {'Content-Type': 'text/plain'});
// 發(fā)送響應(yīng)數(shù)據(jù) "Hello World"
response.end('Hello World\n');
}).listen(8888);
// 終端打印如下信息
console.log('Server running at http://127.0.0.1:8888/');
以上代碼我們完成了一個(gè)可以工作的 HTTP 服務(wù)器。
使用 node 命令執(zhí)行以上的代碼:
node server.js
接下來(lái),打開(kāi)瀏覽器訪問(wèn) http://127.0.0.1:8888/,你會(huì)看到一個(gè)寫(xiě)著 "Hello World"的網(wǎng)頁(yè)。 分析Node.js 的 HTTP 服務(wù)器:
第一行請(qǐng)求(require)Node.js 自帶的 http 模塊,并且把它賦值給 http 變量。接下來(lái)我們調(diào)用 http 模塊提供的函數(shù): createServer 。這個(gè)函數(shù)會(huì)返回 一個(gè)對(duì)象,這個(gè)對(duì)象有一個(gè)叫做 listen 的方法,這個(gè)方法有一個(gè)數(shù)值參數(shù), 指定這個(gè) HTTP 服務(wù)器監(jiān)聽(tīng)的端口號(hào)。
NPM 使用介紹
NPM是隨同NodeJS一起安裝的包管理工具,能解決NodeJS代碼部署上的很多問(wèn)題。
可以通過(guò)輸入 “npm -v” 來(lái)測(cè)試是否成功安裝。
使用 npm 命令安裝模塊
以下實(shí)例,我們使用 npm 命令安裝常用的 Node.js web框架模塊 express:
npm install express
安裝好之后,express 包就放在了工程目錄下的 node_modules 目錄中,因此在代碼中只需要通過(guò) require(‘express’) 的方式就好,無(wú)需指定第三方包路徑。
var express = require('express');
本地安裝
將安裝包放在 ./node_modules 下(運(yùn)行 npm 命令時(shí)所在的目錄),如果沒(méi)有 node_modules 目錄,會(huì)在當(dāng)前執(zhí)行 npm 命令的目錄下生成 node_modules 目錄??梢酝ㄟ^(guò) require() 來(lái)引入本地安裝的包。
使用 package.json
package.json 位于模塊的目錄下,用于定義包的屬性。
模塊的操作
卸載模塊
npm uninstall express
卸載后,你可以到 /node_modules/ 目錄下查看包是否還存在,或者使用以下命令查看:
npm ls
更新模塊
npm update express
搜索模塊
npm search express
回調(diào)函數(shù)
Node.js 異步編程的直接體現(xiàn)就是回調(diào)。
異步編程依托于回調(diào)來(lái)實(shí)現(xiàn),但不能說(shuō)使用了回調(diào)后程序就異步化了。
回調(diào)函數(shù)在完成任務(wù)后就會(huì)被調(diào)用,Node 使用了大量的回調(diào)函數(shù),Node 所有 API 都支持回調(diào)函數(shù)。
例如,我們可以一邊讀取文件,一邊執(zhí)行其他命令,在文件讀取完成后,我們將文件內(nèi)容作為回調(diào)函數(shù)的參數(shù)返回。這樣在執(zhí)行代碼時(shí)就沒(méi)有阻塞或等待文件 I/O 操作。這就大大提高了 Node.js 的性能,可以處理大量的并發(fā)請(qǐng)求。
回調(diào)函數(shù)一般作為函數(shù)的最后一個(gè)參數(shù)出現(xiàn):
function foo1(name, age, callback) { }
function foo2(value, callback1, callback2) { }
阻塞代碼實(shí)例
創(chuàng)建一個(gè)文件 input.txt ,內(nèi)容如下:
菜鳥(niǎo)教程官網(wǎng)地址:www.runoob.com
創(chuàng)建 main.js 文件, 代碼如下:
var fs = require("fs");
var data = fs.readFileSync('input.txt');
console.log(data.toString());
console.log("程序執(zhí)行結(jié)束!");
以上代碼執(zhí)行結(jié)果如下:
非阻塞代碼
創(chuàng)建 main.js 文件, 代碼如下:
var fs = require("fs");
fs.readFile('input.txt', function (err, data) {
if (err) return console.error(err);
console.log(data.toString());
});
console.log("程序執(zhí)行結(jié)束!");
以上兩個(gè)實(shí)例我們了解了阻塞與非阻塞調(diào)用的不同。第一個(gè)實(shí)例在文件讀取完后才執(zhí)行程序。 第二個(gè)實(shí)例我們不需要等待文件讀取完,這樣就可以在讀取文件時(shí)同時(shí)執(zhí)行接下來(lái)的代碼,大大提高了程序的性能。
因此,阻塞是按順序執(zhí)行的,而非阻塞是不需要按順序的,所以如果需要處理回調(diào)函數(shù)的參數(shù),我們就需要寫(xiě)在回調(diào)函數(shù)內(nèi)。
事件循環(huán)
事件驅(qū)動(dòng)程序
Node.js 使用事件驅(qū)動(dòng)模型,當(dāng)web server接收到請(qǐng)求,就把它關(guān)閉然后進(jìn)行處理,然后去服務(wù)下一個(gè)web請(qǐng)求。
當(dāng)這個(gè)請(qǐng)求完成,它被放回處理隊(duì)列,當(dāng)?shù)竭_(dá)隊(duì)列開(kāi)頭,這個(gè)結(jié)果被返回給用戶(hù)。
這個(gè)模型非常高效可擴(kuò)展性非常強(qiáng),因?yàn)?webserver 一直接受請(qǐng)求而不等待任何讀寫(xiě)操作。
在事件驅(qū)動(dòng)模型中,會(huì)生成一個(gè)主循環(huán)來(lái)監(jiān)聽(tīng)事件,當(dāng)檢測(cè)到事件時(shí)觸發(fā)回調(diào)函數(shù)。
Node.js 有多個(gè)內(nèi)置的事件,我們可以通過(guò)引入 events 模塊,并通過(guò)實(shí)例化 EventEmitter 類(lèi)來(lái)綁定和監(jiān)聽(tīng)事件,如下實(shí)例:
創(chuàng)建 main.js 文件,代碼如下所示:
// 引入 events 模塊
var events = require('events');
// 創(chuàng)建 eventEmitter 對(duì)象
var eventEmitter = new events.EventEmitter();
// 創(chuàng)建事件處理程序
var connectHandler = function connected() {
console.log('連接成功。');
// 觸發(fā) data_received 事件
eventEmitter.emit('data_received');
}
// 綁定 connection 事件處理程序
eventEmitter.on('connection', connectHandler);
// 使用匿名函數(shù)綁定 data_received 事件
eventEmitter.on('data_received', function(){
console.log('數(shù)據(jù)接收成功。');
});
// 觸發(fā) connection 事件
eventEmitter.emit('connection');
console.log("程序執(zhí)行完畢。");
EventEmitter
Node.js 所有的異步 I/O 操作在完成時(shí)都會(huì)發(fā)送一個(gè)事件到事件隊(duì)列。
EventEmitter 類(lèi)
events 模塊只提供了一個(gè)對(duì)象: events.EventEmitter。EventEmitter 的核心就是事件觸發(fā)與事件監(jiān)聽(tīng)器功能的封裝。
你可以通過(guò)require(“events”);來(lái)訪問(wèn)該模塊。
// 引入 events 模塊
var events = require('events');
// 創(chuàng)建 eventEmitter 對(duì)象
var eventEmitter = new events.EventEmitter();
下面我們用一個(gè)簡(jiǎn)單的例子說(shuō)明 EventEmitter 的用法:
//event.js 文件
var EventEmitter = require('events').EventEmitter;
var event = new EventEmitter();
event.on('some_event', function() {
console.log('some_event 事件觸發(fā)');
});
setTimeout(function() {
event.emit('some_event');
}, 1000);
運(yùn)行這段代碼,1 秒后控制臺(tái)輸出了 ‘some_event 事件觸發(fā)’。
其原理是 event 對(duì)象注冊(cè)了事件 some_event 的一個(gè)監(jiān)聽(tīng)器,然后我們通過(guò) setTimeout 在 1000 毫秒以后向 event 對(duì)象發(fā)送事件 some_event,此時(shí)會(huì)調(diào)用some_event 的監(jiān)聽(tīng)器。
EventEmitter 的每個(gè)事件由一個(gè)事件名和若干個(gè)參數(shù)組成,事件名是一個(gè)字符串,通常表達(dá)一定的語(yǔ)義。對(duì)于每個(gè)事件,EventEmitter 支持 若干個(gè)事件監(jiān)聽(tīng)器。
當(dāng)事件觸發(fā)時(shí),注冊(cè)到這個(gè)事件的事件監(jiān)聽(tīng)器被依次調(diào)用,事件參數(shù)作為回調(diào)函數(shù)參數(shù)傳遞。
讓我們以下面的例子解釋這個(gè)過(guò)程:
//event.js 文件
var events = require('events');
var emitter = new events.EventEmitter();
emitter.on('someEvent', function(arg1, arg2) {
console.log('listener1', arg1, arg2);
});
emitter.on('someEvent', function(arg1, arg2) {
console.log('listener2', arg1, arg2);
});
emitter.emit('someEvent', 'arg1 參數(shù)', 'arg2 參數(shù)');
以上例子中,emitter 為事件 someEvent 注冊(cè)了兩個(gè)事件監(jiān)聽(tīng)器,然后觸發(fā)了 someEvent 事件。
運(yùn)行結(jié)果中可以看到兩個(gè)事件監(jiān)聽(tīng)器回調(diào)函數(shù)被先后調(diào)用。 這就是EventEmitter最簡(jiǎn)單的用法。
EventEmitter 提供了多個(gè)屬性,如 on 和 emit。on 函數(shù)用于綁定事件函數(shù),emit 屬性用于觸發(fā)一個(gè)事件。接下來(lái)我們來(lái)具體看下 EventEmitter 的屬性介紹。
方法
addListener(event, listener) 為指定事件添加一個(gè)監(jiān)聽(tīng)器到監(jiān)聽(tīng)器數(shù)組的尾部。on(event, listener) 為指定事件注冊(cè)一個(gè)監(jiān)聽(tīng)器,接受一個(gè)字符串 event 和一個(gè)回調(diào)函數(shù)。
server.on('connection', function (stream) {
console.log('someone connected!');
});
once(event, listener) 為指定事件注冊(cè)一個(gè)單次監(jiān)聽(tīng)器,即 監(jiān)聽(tīng)器最多只會(huì)觸發(fā)一次,觸發(fā)后立刻解除該監(jiān)聽(tīng)器。
server.once('connection', function (stream) {
console.log('Ah, we have our first user!');
});
removeListener(event, listener) 移除指定事件的某個(gè)監(jiān)聽(tīng)器,監(jiān)聽(tīng)器必須是該事件已經(jīng)注冊(cè)過(guò)的監(jiān)聽(tīng)器。
它接受兩個(gè)參數(shù),第一個(gè)是事件名稱(chēng),第二個(gè)是回調(diào)函數(shù)名稱(chēng)。
var callback = function(stream) {
console.log('someone connected!');
};
server.on('connection', callback);
// ...
server.removeListener('connection', callback);
類(lèi)方法 listenerCount(emitter, event) 返回指定事件的監(jiān)聽(tīng)器數(shù)量。
events.emitter.listenerCount(eventName) //推薦
實(shí)例
以下實(shí)例通過(guò) connection(連接)事件演示了 EventEmitter 類(lèi)的應(yīng)用。
創(chuàng)建 main.js 文件,代碼如下:
var events = require('events');
var eventEmitter = new events.EventEmitter();
// 監(jiān)聽(tīng)器 #1
var listener1 = function listener1() {
console.log('監(jiān)聽(tīng)器 listener1 執(zhí)行。');
}
// 監(jiān)聽(tīng)器 #2
var listener2 = function listener2() {
console.log('監(jiān)聽(tīng)器 listener2 執(zhí)行。');
}
// 綁定 connection 事件,處理函數(shù)為 listener1
eventEmitter.addListener('connection', listener1);
// 綁定 connection 事件,處理函數(shù)為 listener2
eventEmitter.on('connection', listener2);
var eventListeners = eventEmitter.listenerCount('connection');
console.log(eventListeners + " 個(gè)監(jiān)聽(tīng)器監(jiān)聽(tīng)連接事件。");
// 處理 connection 事件
eventEmitter.emit('connection');
// 移除監(jiān)綁定的 listener1 函數(shù)
eventEmitter.removeListener('connection', listener1);
console.log("listener1 不再受監(jiān)聽(tīng)。");
// 觸發(fā)連接事件
eventEmitter.emit('connection');
eventListeners = eventEmitter.listenerCount('connection');
console.log(eventListeners + " 個(gè)監(jiān)聽(tīng)器監(jiān)聽(tīng)連接事件。");
console.log("程序執(zhí)行完畢。");
error 事件
EventEmitter 定義了一個(gè)特殊的事件 error,它包含了錯(cuò)誤的語(yǔ)義,我們?cè)谟龅?異常的時(shí)候通常會(huì)觸發(fā) error 事件。 我們一般要為會(huì)觸發(fā) error 事件的對(duì)象設(shè)置監(jiān)聽(tīng)器,避免遇到錯(cuò)誤后整個(gè)程序崩潰。例如:
var events = require('events');
var emitter = new events.EventEmitter();
emitter.emit('error');
繼承 EventEmitter
大多數(shù)時(shí)候我們不會(huì)直接使用 EventEmitter,而是在對(duì)象中繼承它。包括 fs、net、 http 在內(nèi)的,只要是支持事件響應(yīng)的核心模塊都是 EventEmitter 的子類(lèi)。
Buffer(緩沖區(qū))
在 Node.js 中,Buffer 類(lèi)是隨 Node 內(nèi)核一起發(fā)布的核心庫(kù)。Buffer 庫(kù)為 Node.js 帶來(lái)了一種存儲(chǔ)原始數(shù)據(jù)的方法,可以讓 Node.js 處理二進(jìn)制數(shù)據(jù),每當(dāng)需要在 Node.js 中處理I/O操作中移動(dòng)的數(shù)據(jù)時(shí),就有可能使用 Buffer 庫(kù)。
Buffer 與字符編碼
Buffer 實(shí)例一般用于表示編碼字符的序列,比如 UTF-8 、 UCS2 、 Base64 、或十六進(jìn)制編碼的數(shù)據(jù)。
const buf = Buffer.from('runoob', 'ascii');
// 輸出 72756e6f6f62
console.log(buf.toString('hex'));
// 輸出 cnVub29i
console.log(buf.toString('base64'));
創(chuàng)建 Buffer 類(lèi)
Buffer 提供了以下 API 來(lái)創(chuàng)建 Buffer 類(lèi):
// 創(chuàng)建一個(gè)長(zhǎng)度為 10、且用 0 填充的 Buffer。
const buf1 = Buffer.alloc(10);
// 創(chuàng)建一個(gè)長(zhǎng)度為 10、且用 0x1 填充的 Buffer。
const buf2 = Buffer.alloc(10, 1);
// 創(chuàng)建一個(gè)長(zhǎng)度為 10、且未初始化的 Buffer。
// 這個(gè)方法比調(diào)用 Buffer.alloc() 更快,
// 但返回的 Buffer 實(shí)例可能包含舊數(shù)據(jù),
// 因此需要使用 fill() 或 write() 重寫(xiě)。
const buf3 = Buffer.allocUnsafe(10);
// 創(chuàng)建一個(gè)包含 [0x1, 0x2, 0x3] 的 Buffer。
const buf4 = Buffer.from([1, 2, 3]);
// 創(chuàng)建一個(gè)包含 UTF-8 字節(jié) [0x74, 0xc3, 0xa9, 0x73, 0x74] 的 Buffer。
const buf5 = Buffer.from('tést');
// 創(chuàng)建一個(gè)包含 Latin-1 字節(jié) [0x74, 0xe9, 0x73, 0x74] 的 Buffer。
const buf6 = Buffer.from('tést', 'latin1');
寫(xiě)入緩沖區(qū)
語(yǔ)法:
buf.write(string[, offset[, length]][, encoding])
參數(shù):
string - 寫(xiě)入緩沖區(qū)的字符串。 offset - 緩沖區(qū)開(kāi)始寫(xiě)入的索引值,默認(rèn)為 0 。 length - 寫(xiě)入的字節(jié)數(shù),默認(rèn)為 buffer.length encoding - 使用的編碼。默認(rèn)為 ‘utf8’ 。 根據(jù) encoding 的字符編碼寫(xiě)入 string 到 buf 中的 offset 位置。 length 參數(shù)是寫(xiě)入的字節(jié)數(shù)。 返回值 返回實(shí)際寫(xiě)入的大小。 實(shí)例
buf = Buffer.alloc(256);
len = buf.write("www.runoob.com");
console.log("寫(xiě)入字節(jié)數(shù) : "+ len);
從緩沖區(qū)讀取數(shù)據(jù)
語(yǔ)法
buf.toString([encoding[, start[, end]]])
參數(shù)
encoding - 使用的編碼。默認(rèn)為 ‘utf8’ 。 start - 指定開(kāi)始讀取的索引位置,默認(rèn)為 0。 end - 結(jié)束位置,默認(rèn)為緩沖區(qū)的末尾。
返回值 解碼緩沖區(qū)數(shù)據(jù)并使用指定的編碼返回字符串。
實(shí)例
buf = Buffer.alloc(26);
for (var i = 0 ; i < 26 ; i++) {
buf[i] = i + 97;
}
console.log( buf.toString('ascii')); // 輸出: abcdefghijklmnopqrstuvwxyz
console.log( buf.toString('ascii',0,5)); //使用 'ascii' 編碼, 并輸出: abcde
console.log( buf.toString('utf8',0,5)); // 使用 'utf8' 編碼, 并輸出: abcde
console.log( buf.toString(undefined,0,5)); // 使用默認(rèn)的 'utf8' 編碼, 并輸出: abcde
將 Buffer 轉(zhuǎn)換為 JSON 對(duì)象
語(yǔ)法
buf.toJSON()
返回值 返回 JSON 對(duì)象。
實(shí)例
const buf = Buffer.from([0x1, 0x2, 0x3, 0x4, 0x5]);
const json = JSON.stringify(buf);
// 輸出: {"type":"Buffer","data":[1,2,3,4,5]}
console.log(json);
const copy = JSON.parse(json, (key, value) => {
return value && value.type === 'Buffer' ?
Buffer.from(value.data) :
value;
});
// 輸出:
console.log(copy);
JSON 通常用于與服務(wù)端交換數(shù)據(jù)。 我們可以使用 JSON.parse() 方法將數(shù)據(jù)轉(zhuǎn)換為 JavaScript 對(duì)象。
緩沖區(qū)合并
語(yǔ)法
Buffer.concat(list[, totalLength])
參數(shù)
list - 用于合并的 Buffer 對(duì)象數(shù)組列表。 totalLength - 指定合并后Buffer對(duì)象的總長(zhǎng)度。
返回值 返回一個(gè)多個(gè)成員合并的新 Buffer 對(duì)象。
實(shí)例
var buffer1 = Buffer.from(('菜鳥(niǎo)教程'));
var buffer2 = Buffer.from(('www.runoob.com'));
var buffer3 = Buffer.concat([buffer1,buffer2]);
console.log("buffer3 內(nèi)容: " + buffer3.toString());
緩沖區(qū)比較
語(yǔ)法
buf.compare(otherBuffer);
參數(shù)
otherBuffer - 與 buf 對(duì)象比較的另外一個(gè) Buffer 對(duì)象。
返回值 返回一個(gè)數(shù)字,表示 buf 在 otherBuffer 之前,之后或相同。
實(shí)例
var buffer1 = Buffer.from('ABC');
var buffer2 = Buffer.from('ABCD');
var result = buffer1.compare(buffer2);
if(result < 0) {
console.log(buffer1 + " 在 " + buffer2 + "之前");
}else if(result == 0){
console.log(buffer1 + " 與 " + buffer2 + "相同");
}else {
console.log(buffer1 + " 在 " + buffer2 + "之后");
}
拷貝緩沖區(qū)
語(yǔ)法
buf.copy(targetBuffer[, targetStart[, sourceStart[, sourceEnd]]])
參數(shù)
targetBuffer - 要拷貝的 Buffer 對(duì)象。 targetStart - 數(shù)字, 可選, 默認(rèn): 0 sourceStart - 數(shù)字, 可選, 默認(rèn): 0 sourceEnd - 數(shù)字, 可選, 默認(rèn): buffer.length
實(shí)例
var buf1 = Buffer.from('abcdefghijkl');
var buf2 = Buffer.from('RUNOOB');
//將 buf2 插入到 buf1 指定位置上
buf2.copy(buf1, 2);
console.log(buf1.toString());
緩沖區(qū)裁剪
語(yǔ)法
buf.slice([start[, end]])
參數(shù)
start - 數(shù)字, 可選, 默認(rèn): 0 end - 數(shù)字, 可選, 默認(rèn): buffer.length
返回值 返回一個(gè)新的緩沖區(qū),它和舊緩沖區(qū)指向同一塊內(nèi)存,但是從索引 start 到 end 的位置剪切。
實(shí)例
var buffer1 = Buffer.from('runoob');
// 剪切緩沖區(qū)
var buffer2 = buffer1.slice(0,2);
console.log("buffer2 content: " + buffer2.toString());
緩沖區(qū)長(zhǎng)度
語(yǔ)法
buf.length;
返回值 返回 Buffer 對(duì)象所占據(jù)的內(nèi)存長(zhǎng)度。
實(shí)例
var buffer = Buffer.from('www.runoob.com');
// 緩沖區(qū)長(zhǎng)度
console.log("buffer length: " + buffer.length);
Stream(流)
Stream 是一個(gè)抽象接口,Node 中有很多對(duì)象實(shí)現(xiàn)了這個(gè)接口。
所有的 Stream 對(duì)象都是 EventEmitter 的實(shí)例。常用的事件有:
data - 當(dāng)有數(shù)據(jù)可讀時(shí)觸發(fā)。 end - 沒(méi)有更多的數(shù)據(jù)可讀時(shí)觸發(fā)。 error - 在接收和寫(xiě)入過(guò)程中發(fā)生錯(cuò)誤時(shí)觸發(fā)。 finish - 所有數(shù)據(jù)已被寫(xiě)入到底層系統(tǒng)時(shí)觸發(fā)。
從流中讀取數(shù)據(jù)
創(chuàng)建 input.txt 文件,內(nèi)容如下:
菜鳥(niǎo)教程官網(wǎng)地址:www.runoob.com
創(chuàng)建 main.js 文件, 代碼如下:
var fs = require("fs");
var data = '';
// 創(chuàng)建可讀流
var readerStream = fs.createReadStream('input.txt');
// 設(shè)置編碼為 utf8。
readerStream.setEncoding('UTF8');
// 處理流事件 --> data, end, and error
readerStream.on('data', function(chunk) {
data += chunk;
});
readerStream.on('end',function(){
console.log(data);
});
readerStream.on('error', function(err){
console.log(err.stack);
});
console.log("程序執(zhí)行完畢");
寫(xiě)入流
var fs = require("fs");
var data = '菜鳥(niǎo)教程官網(wǎng)地址:www.runoob.com';
// 創(chuàng)建一個(gè)可以寫(xiě)入的流,寫(xiě)入到文件 output.txt 中
var writerStream = fs.createWriteStream('output.txt');
// 使用 utf8 編碼寫(xiě)入數(shù)據(jù)
writerStream.write(data,'UTF8');
// 標(biāo)記文件末尾
writerStream.end();
// 處理流事件 --> finish、error
writerStream.on('finish', function() {
console.log("寫(xiě)入完成。");
});
writerStream.on('error', function(err){
console.log(err.stack);
});
console.log("程序執(zhí)行完畢");
管道流
管道提供了一個(gè)輸出流到輸入流的機(jī)制。通常我們用于從一個(gè)流中獲取數(shù)據(jù)并將數(shù)據(jù)傳遞到另外一個(gè)流中。
以下實(shí)例我們通過(guò)讀取一個(gè)文件內(nèi)容并將內(nèi)容寫(xiě)入到另外一個(gè)文件中。
設(shè)置 input.txt 文件內(nèi)容如下:
菜鳥(niǎo)教程官網(wǎng)地址:www.runoob.com
管道流操作實(shí)例
創(chuàng)建 main.js 文件, 代碼如下:
var fs = require("fs");
// 創(chuàng)建一個(gè)可讀流
var readerStream = fs.createReadStream('input.txt');
// 創(chuàng)建一個(gè)可寫(xiě)流
var writerStream = fs.createWriteStream('output.txt');
// 管道讀寫(xiě)操作
// 讀取 input.txt 文件內(nèi)容,并將內(nèi)容寫(xiě)入到 output.txt 文件中
readerStream.pipe(writerStream);
console.log("程序執(zhí)行完畢");
鏈?zhǔn)搅?/p>
鏈?zhǔn)绞峭ㄟ^(guò)連接輸出流到另外一個(gè)流并創(chuàng)建多個(gè)流操作鏈的機(jī)制。鏈?zhǔn)搅饕话阌糜诠艿啦僮鳌?/p>
接下來(lái)我們就是用管道和鏈?zhǔn)絹?lái)壓縮和解壓文件。
創(chuàng)建 compress.js 文件, 代碼如下:
var fs = require("fs");
var zlib = require('zlib');
// 壓縮 input.txt 文件為 input.txt.gz
fs.createReadStream('input.txt')
.pipe(zlib.createGzip())
.pipe(fs.createWriteStream('input.txt.gz'));
console.log("文件壓縮完成。");
執(zhí)行完以上操作后,我們可以看到當(dāng)前目錄下生成了 input.txt 的壓縮文件 input.txt.gz。
接下來(lái),讓我們來(lái)解壓該文件,創(chuàng)建 decompress.js 文件,代碼如下:
var fs = require("fs");
var zlib = require('zlib');
// 解壓 input.txt.gz 文件為 input.txt
fs.createReadStream('input.txt.gz')
.pipe(zlib.createGunzip())
.pipe(fs.createWriteStream('input.txt'));
console.log("文件解壓完成。");
模塊系統(tǒng)
一個(gè) Node.js 文件就是一個(gè)模塊,這個(gè)文件可能是JavaScript 代碼、JSON 或者編譯過(guò)的C/C++ 擴(kuò)展。
引入模塊
我們創(chuàng)建一個(gè) main.js 文件并引入 hello 模塊,代碼如下:
var hello = require('./hello');
hello.world();
以上實(shí)例中,代碼 require(‘./hello’) 引入了當(dāng)前目錄下的 hello.js 文件(./ 為當(dāng)前目錄,node.js 默認(rèn)后綴為 js)。
接下來(lái)我們就來(lái)創(chuàng)建 hello.js 文件,代碼如下:
exports.world = function() {
console.log('Hello World');
}
有時(shí)候我們只是想把一個(gè)對(duì)象封裝到模塊中,格式如下:
//hello.js
function Hello() {
var name;
this.setName = function(thyName) {
name = thyName;
};
this.sayHello = function() {
console.log('Hello ' + name);
};
};
module.exports = Hello;
這樣就可以直接獲得這個(gè)對(duì)象了:
//main.js
var Hello = require('./hello');
hello = new Hello();
hello.setName('BYVoid');
hello.sayHello();
函數(shù)
在 JavaScript中,一個(gè)函數(shù)可以作為另一個(gè)函數(shù)的參數(shù)。我們可以先定義一個(gè)函數(shù),然后傳遞,也可以在傳遞參數(shù)的地方直接定義函數(shù)。
function say(word) {
console.log(word);
}
function execute(someFunction, value) {
someFunction(value);
}
execute(say, "Hello");
以上代碼中,我們把 say 函數(shù)作為 execute 函數(shù)的第一個(gè)變量進(jìn)行了傳遞。這里傳遞的不是 say 的返回值,而是 say 本身!
這樣一來(lái), say 就變成了execute 中的本地變量 someFunction ,execute 可以通過(guò)調(diào)用 someFunction() (帶括號(hào)的形式)來(lái)使用 say 函數(shù)。
當(dāng)然,因?yàn)?say 有一個(gè)變量, execute 在調(diào)用 someFunction 時(shí)可以傳遞這樣一個(gè)變量。
匿名函數(shù)
我們可以把一個(gè)函數(shù)作為變量傳遞。但是我們不一定要"先定義,再傳遞"。
我們可以直接在另一個(gè)函數(shù)的括號(hào)中定義和傳遞這個(gè)函數(shù):
function execute(someFunction, value) {
someFunction(value);
}
execute(function(word){ console.log(word) }, "Hello");
我們?cè)?execute 接受第一個(gè)參數(shù)的地方直接定義了我們準(zhǔn)備傳遞給 execute 的函數(shù)。
用這種方式,我們甚至不用給這個(gè)函數(shù)起名字,這也是為什么它被叫做匿名函數(shù) 。
函數(shù)傳遞是如何讓 HTTP 服務(wù)器工作的
var http = require("http");
http.createServer(function(request, response) {
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hello World");
response.end();
}).listen(8888);
現(xiàn)在它看上去應(yīng)該清晰了很多:我們向 createServer 函數(shù)傳遞了一個(gè)匿名函數(shù)。
路由
我們需要的所有數(shù)據(jù)都會(huì)包含在 request 對(duì)象中,該對(duì)象作為 onRequest() 回調(diào)函數(shù)的第一個(gè)參數(shù)傳遞。
但是為了解析這些數(shù)據(jù),我們需要額外的 Node.JS 模塊,它們分別是 url 和 querystring 模塊。
url.parse(string).query
|
url.parse(string).pathname |
| |
| |
------|-------------------
http://localhost:8888/start?foo=bar&hello=world
--- -----
| |
| |
querystring.parse(queryString)["foo"] |
|
querystring.parse(queryString)["hello"]
現(xiàn)在我們來(lái)給 onRequest() 函數(shù)加上一些邏輯,用來(lái)找出瀏覽器請(qǐng)求的 URL 路徑:
var http = require("http");
var url = require("url");
function start() {
function onRequest(request, response) {
var pathname = url.parse(request.url).pathname;
console.log("Request for " + pathname + " received.");
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hello World");
response.end();
}
http.createServer(onRequest).listen(8888);
console.log("Server has started.");
}
exports.start = start;
現(xiàn)在我們可以來(lái)編寫(xiě)路由了,建立一個(gè)名為 router.js 的文件,添加以下內(nèi)容:
function route(pathname) {
console.log("About to route a request for " + pathname);
}
exports.route = route;
如你所見(jiàn),這段代碼什么也沒(méi)干,不過(guò)對(duì)于現(xiàn)在來(lái)說(shuō)這是應(yīng)該的。在添加更多的邏輯以前,我們先來(lái)看看如何把路由和服務(wù)器整合起來(lái)。
首先,我們來(lái)擴(kuò)展一下服務(wù)器的 start() 函數(shù),以便將路由函數(shù)作為參數(shù)傳遞過(guò)去,server.js 文件代碼如下
var http = require("http");
var url = require("url");
function start(route) {
function onRequest(request, response) {
var pathname = url.parse(request.url).pathname;
console.log("Request for " + pathname + " received.");
route(pathname);
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hello World");
response.end();
}
http.createServer(onRequest).listen(8888);
console.log("Server has started.");
}
exports.start = start;
同時(shí),我們會(huì)相應(yīng)擴(kuò)展 index.js,使得路由函數(shù)可以被注入到服務(wù)器中:
var server = require("./server");
var router = require("./router");
server.start(router.route);
如果現(xiàn)在啟動(dòng)應(yīng)用(node index.js,始終記得這個(gè)命令行),隨后請(qǐng)求一個(gè)URL,你將會(huì)看到應(yīng)用輸出相應(yīng)的信息,這表明我們的HTTP服務(wù)器已經(jīng)在使用路由模塊了,并會(huì)將請(qǐng)求的路徑傳遞給路由:
瀏覽器訪問(wèn) http://127.0.0.1:8888/,輸出結(jié)果如下:
全局對(duì)象
全局對(duì)象(Global Object),它及其所有屬性都可以在程序的任何地方訪問(wèn)。
Node.js 中的全局對(duì)象是 global,所有全局變量都是 global 對(duì)象的屬性。
在 Node.js 我們可以直接訪問(wèn)到 global 的屬性,而不需要在應(yīng)用中包含它。
__filename
__filename 表示當(dāng)前正在執(zhí)行的腳本的文件名。它將輸出文件所在位置的絕對(duì)路徑。
實(shí)例 創(chuàng)建文件 main.js ,代碼如下所示:
// 輸出全局變量 __filename 的值
console.log( __filename );
__dirname
__dirname 表示當(dāng)前執(zhí)行腳本所在的目錄。
實(shí)例 創(chuàng)建文件 main.js ,代碼如下所示:
// 輸出全局變量 __dirname 的值
console.log( __dirname );
setTimeout(cb, ms)
setTimeout(cb, ms) 全局函數(shù)在指定的毫秒(ms)數(shù)后執(zhí)行指定函數(shù)(cb)。 實(shí)例
function printHello(){
console.log( "Hello, World!");
}
// 兩秒后執(zhí)行以上函數(shù)
setTimeout(printHello, 2000);
兩秒后輸出:
clearTimeout(t)
clearTimeout( t ) 全局函數(shù)用于停止一個(gè)之前通過(guò) setTimeout() 創(chuàng)建的定時(shí)器。
參數(shù) t 是通過(guò) setTimeout() 函數(shù)創(chuàng)建的定時(shí)器。
實(shí)例
function printHello(){
console.log( "Hello, World!");
}
// 兩秒后執(zhí)行以上函數(shù)
var t = setTimeout(printHello, 2000);
// 清除定時(shí)器
clearTimeout(t);
setInterval(cb, ms)
setInterval(cb, ms) 全局函數(shù)在指定的毫秒(ms)數(shù)后執(zhí)行指定函數(shù)(cb)。
可以使用 clearInterval(t) 函數(shù)來(lái)清除定時(shí)器。
setInterval() 方法會(huì)不停地調(diào)用函數(shù),直到 clearInterval() 被調(diào)用或窗口被關(guān)閉。
實(shí)例
function printHello(){
console.log( "Hello, World!");
}
// 兩秒后執(zhí)行以上函數(shù)
setInterval(printHello, 2000);
以上程序每隔兩秒就會(huì)輸出一次"Hello, World!",且會(huì)永久執(zhí)行下去,直到你按下 ctrl + c 按鈕。
console
console 用于提供控制臺(tái)標(biāo)準(zhǔn)輸出。
console.log([data][, …]) 向標(biāo)準(zhǔn)輸出流打印字符并以換行符結(jié)束。console.info([data][, …]) 這個(gè)命令與console.log差別并不大console.time(label) 輸出時(shí)間,表示計(jì)時(shí)開(kāi)始。console.timeEnd(label) 結(jié)束時(shí)間,表示計(jì)時(shí)結(jié)束。
實(shí)例
console.info("程序開(kāi)始執(zhí)行:");
var counter = 10;
console.log("計(jì)數(shù): %d", counter);
console.time("獲取數(shù)據(jù)");
//
// 執(zhí)行一些代碼
//
console.timeEnd('獲取數(shù)據(jù)');
console.info("程序執(zhí)行完畢。")
process
process 是一個(gè)全局變量,即 global 對(duì)象的屬性。
它用于描述當(dāng)前Node.js 進(jìn)程狀態(tài)的對(duì)象,提供了一個(gè)與操作系統(tǒng)的簡(jiǎn)單接口。
實(shí)例 Process 對(duì)象的常用的成員方法:exit 當(dāng)進(jìn)程準(zhǔn)備退出時(shí)觸發(fā)。
process.on('exit', function(code) {
// 以下代碼永遠(yuǎn)不會(huì)執(zhí)行
setTimeout(function() {
console.log("該代碼不會(huì)執(zhí)行");
}, 0);
console.log('退出碼為:', code);
});
console.log("程序執(zhí)行結(jié)束");
Process 屬性
stdout 標(biāo)準(zhǔn)輸出流。argv argv 屬性返回一個(gè)數(shù)組,由命令行執(zhí)行腳本時(shí)的各個(gè)參數(shù)組成。 它的第一個(gè)成員總是node,第二個(gè)成員是腳本文件名,其余成員是腳本文件的參數(shù)。execPath 返回執(zhí)行當(dāng)前腳本的 Node 二進(jìn)制文件的絕對(duì)路徑。platform 運(yùn)行程序所在的平臺(tái)系統(tǒng) ‘darwin’, ‘freebsd’, ‘linux’, ‘sunos’ 或 ‘win32’
// 輸出到終端
process.stdout.write("Hello World!" + "\n");
// 通過(guò)參數(shù)讀取
process.argv.forEach(function(val, index, array) {
console.log(index + ': ' + val);
});
// 獲取執(zhí)行路徑
console.log(process.execPath);
// 平臺(tái)信息
console.log(process.platform);
方法參考手冊(cè)
// 輸出當(dāng)前目錄
console.log('當(dāng)前目錄: ' + process.cwd());
// 輸出當(dāng)前版本
console.log('當(dāng)前版本: ' + process.version);
// 輸出內(nèi)存使用情況
console.log(process.memoryUsage());
常用工具
util 是一個(gè)Node.js 核心模塊,提供常用函數(shù)的集合。
使用方法如下:
const util = require('util');
util.callbackify
util.callbackify(original) 將 async 異步函數(shù)(或者一個(gè)返回值為 Promise 的函數(shù))轉(zhuǎn)換成遵循異常優(yōu)先的回調(diào)風(fēng)格的函數(shù)。
const util = require('util');
async function fn() {
return 'hello world';
}
const callbackFunction = util.callbackify(fn);
callbackFunction((err, ret) => {
if (err) throw err;
console.log(ret);
});
util.inherits
util.inherits(constructor, superConstructor) 是一個(gè)實(shí)現(xiàn)對(duì)象間原型繼承的函數(shù)。
var util = require('util');
function Base() {
this.name = 'base';
this.base = 1991;
this.sayHello = function() {
console.log('Hello ' + this.name);
};
}
Base.prototype.showName = function() {
console.log(this.name);
};
function Sub() {
this.name = 'sub';
}
util.inherits(Sub, Base);
var objBase = new Base();
objBase.showName();
objBase.sayHello();
console.log(objBase);
var objSub = new Sub();
objSub.showName();
//objSub.sayHello();
console.log(objSub);
我們定義了一個(gè)基礎(chǔ)對(duì)象 Base 和一個(gè)繼承自 Base 的 Sub。 Base 有三個(gè)在構(gòu)造函數(shù)內(nèi)定義的屬性和一個(gè)原型中定義的函數(shù),通過(guò)util.inherits 實(shí)現(xiàn)繼承。運(yùn)行結(jié)果如下:
注意:Sub 僅僅繼承了Base 在原型中定義的函數(shù),而構(gòu)造函數(shù)內(nèi)部創(chuàng)造的 base 屬性和 sayHello 函數(shù)都沒(méi)有被 Sub 繼承。
如果我們?nèi)サ?objSub.sayHello(); 這行的注釋?zhuān)瑢?huì)看到:
util.inspect
util.inspect(object,[showHidden],[depth],[colors]) 是一個(gè)將任意對(duì)象轉(zhuǎn)換 為字符串的方法。
showHidden 是一個(gè)可選參數(shù),如果值為 true,將會(huì)輸出更多隱藏信息。
var util = require('util');
function Person() {
this.name = 'byvoid';
this.toString = function() {
return this.name;
};
}
var obj = new Person();
console.log(util.inspect(obj));
console.log(util.inspect(obj, true));
util.isArray
如果給定的參數(shù) “object” 是一個(gè)數(shù)組返回 true,否則返回 false。
var util = require('util');
util.isArray([])
// true
util.isArray(new Array)
// true
util.isArray({})
// false
util.isRegExp(object)
如果給定的參數(shù) “object” 是一個(gè)正則表達(dá)式返回true,否則返回false。
var util = require('util');
util.isRegExp(/some regexp/)
// true
util.isRegExp(new RegExp('another regexp'))
// true
util.isRegExp({})
// false
util.isDate(object)
如果給定的參數(shù) “object” 是一個(gè)日期返回true,否則返回false。
var util = require('util');
util.isDate(new Date())
// true
util.isDate(Date())
// false (without 'new' returns a String)
util.isDate({})
// false
文件系統(tǒng)
Node 導(dǎo)入文件系統(tǒng)模塊(fs)語(yǔ)法如下所示:
var fs = require("fs")
異步和同步
異步的方法函數(shù)最后一個(gè)參數(shù)為回調(diào)函數(shù),回調(diào)函數(shù)的第一個(gè)參數(shù)包含了錯(cuò)誤信息(error)。
建議大家使用異步方法,比起同步,異步方法性能更高,速度更快,而且沒(méi)有阻塞。
實(shí)例 創(chuàng)建 input.txt 文件,內(nèi)容如下:
菜鳥(niǎo)教程官網(wǎng)地址:www.runoob.com
文件讀取實(shí)例
創(chuàng)建 file.js 文件, 代碼如下:
var fs = require("fs");
// 異步讀取
fs.readFile('input.txt', function (err, data) {
if (err) {
return console.error(err);
}
console.log("異步讀取: " + data.toString());
});
// 同步讀取
var data = fs.readFileSync('input.txt');
console.log("同步讀取: " + data.toString());
console.log("程序執(zhí)行完畢。");
打開(kāi)文件
語(yǔ)法
fs.open(path, flags[, mode], callback)
參數(shù)
path - 文件的路徑。 flags - 文件打開(kāi)的行為。flags 參數(shù)可以是以下值:
r 以讀取模式打開(kāi)文件。w 以寫(xiě)入模式打開(kāi)文件。r+/w+ 以讀寫(xiě)模式打開(kāi)文件。 mode - 設(shè)置文件模式(權(quán)限),文件創(chuàng)建默認(rèn)權(quán)限為 0666(可讀,可寫(xiě))。 callback - 回調(diào)函數(shù),帶有兩個(gè)參數(shù)如:callback(err, fd)。
實(shí)例 創(chuàng)建 file.js 文件,并打開(kāi) input.txt 文件進(jìn)行讀寫(xiě),代碼如下所示:
var fs = require("fs");
// 異步打開(kāi)文件
console.log("準(zhǔn)備打開(kāi)文件!");
fs.open('input.txt', 'r+', function(err, fd) {
if (err) {
return console.error(err);
}
console.log("文件打開(kāi)成功!");
});
獲取文件信息
語(yǔ)法 以下為通過(guò)異步模式獲取文件信息的語(yǔ)法格式:
fs.stat(path, callback)
參數(shù)
path - 文件路徑。callback - 回調(diào)函數(shù),帶有兩個(gè)參數(shù)如:(err, stats), stats 是 fs.Stats 對(duì)象。
fs.stat(path)執(zhí)行后,會(huì)將 stats 類(lèi)的實(shí)例返回給其回調(diào)函數(shù)??梢酝ㄟ^(guò) stats 類(lèi)中的提供方法判斷文件的相關(guān)屬性。例如判斷是否為文件:
var fs = require('fs');
fs.stat('/Users/liuht/code/itbilu/demo/fs.js', function (err, stats) {
console.log(stats.isFile()); //true
})
實(shí)例
var fs = require("fs");
console.log("準(zhǔn)備打開(kāi)文件!");
fs.stat('input.txt', function (err, stats) {
if (err) {
return console.error(err);
}
console.log(stats);
console.log("讀取文件信息成功!");
// 檢測(cè)文件類(lèi)型
console.log("是否為文件(isFile) ? " + stats.isFile());
console.log("是否為目錄(isDirectory) ? " + stats.isDirectory());
});
寫(xiě)入文件
語(yǔ)法
fs.writeFile(file, data[, options], callback)
writeFile 直接打開(kāi)文件默認(rèn)是 w 模式,所以如果文件存在,該方法寫(xiě)入的內(nèi)容會(huì)覆蓋舊的文件內(nèi)容。 參數(shù)
file - 文件名或文件描述符。 data - 要寫(xiě)入文件的數(shù)據(jù),可以是 String(字符串) 或 Buffer(緩沖) 對(duì)象。 options - 該參數(shù)是一個(gè)對(duì)象,包含 {encoding, mode, flag}。默認(rèn)編碼為 utf8, 模式為 0666 , flag 為 ‘w’ callback - 回調(diào)函數(shù),回調(diào)函數(shù)只包含錯(cuò)誤信息參數(shù)(err),在寫(xiě)入失敗時(shí)返回。
實(shí)例 接下來(lái)我們創(chuàng)建 file.js 文件,代碼如下所示:
var fs = require("fs");
console.log("準(zhǔn)備寫(xiě)入文件");
fs.writeFile('input.txt', '我是通 過(guò)fs.writeFile 寫(xiě)入文件的內(nèi)容', function(err) {
if (err) {
return console.error(err);
}
console.log("數(shù)據(jù)寫(xiě)入成功!");
console.log("--------我是分割線(xiàn)-------------")
console.log("讀取寫(xiě)入的數(shù)據(jù)!");
fs.readFile('input.txt', function (err, data) {
if (err) {
return console.error(err);
}
console.log("異步讀取文件數(shù)據(jù): " + data.toString());
});
});
讀取文件
語(yǔ)法 以下為異步模式下讀取文件的語(yǔ)法格式:
fs.read(fd, buffer, offset, length, position, callback)
參數(shù)
fd - 通過(guò) fs.open() 方法返回的文件描述符。 buffer - 數(shù)據(jù)寫(xiě)入的緩沖區(qū)。 offset - 緩沖區(qū)寫(xiě)入的寫(xiě)入偏移量。 length - 要從文件中讀取的字節(jié)數(shù)。 position - 文件讀取的起始位置,如果 position 的值為 null,則會(huì)從當(dāng)前文件指針的位置讀取。 callback - 回調(diào)函數(shù),有三個(gè)參數(shù)err, bytesRead, buffer,err 為錯(cuò)誤信息, bytesRead 表示讀取的字節(jié)數(shù),buffer 為緩沖區(qū)對(duì)象。
實(shí)例 input.txt 文件內(nèi)容為:
菜鳥(niǎo)教程官網(wǎng)地址:www.runoob.com
file.js
var fs = require("fs");
var buf = new Buffer.alloc(1024);
console.log("準(zhǔn)備打開(kāi)已存在的文件!");
fs.open('input.txt', 'r+', function(err, fd) {
if (err) {
return console.error(err);
}
console.log("文件打開(kāi)成功!");
console.log("準(zhǔn)備讀取文件:");
fs.read(fd, buf, 0, buf.length, 0, function(err, bytes){
if (err){
console.log(err);
}
console.log(bytes + " 字節(jié)被讀取");
// 僅輸出讀取的字節(jié)
if(bytes > 0){
console.log(buf.slice(0, bytes).toString());
}
});
});
關(guān)閉文件
語(yǔ)法
fs.close(fd, callback)
參數(shù)
fd - 通過(guò) fs.open() 方法返回的文件描述符。 callback - 回調(diào)函數(shù),沒(méi)有參數(shù)。
實(shí)例 file.js
var fs = require("fs");
var buf = new Buffer.alloc(1024);
console.log("準(zhǔn)備打開(kāi)文件!");
fs.open('input.txt', 'r+', function(err, fd) {
if (err) {
return console.error(err);
}
console.log("文件打開(kāi)成功!");
console.log("準(zhǔn)備讀取文件!");
fs.read(fd, buf, 0, buf.length, 0, function(err, bytes){
if (err){
console.log(err);
}
// 僅輸出讀取的字節(jié)
if(bytes > 0){
console.log(buf.slice(0, bytes).toString());
}
// 關(guān)閉文件
fs.close(fd, function(err){
if (err){
console.log(err);
}
console.log("文件關(guān)閉成功");
});
});
});
截取文件
語(yǔ)法
fs.ftruncate(fd, len, callback)
參數(shù)
fd - 通過(guò) fs.open() 方法返回的文件描述符。 len - 文件內(nèi)容截取的長(zhǎng)度。 callback - 回調(diào)函數(shù),沒(méi)有參數(shù)。
實(shí)例 input.txt 文件內(nèi)容為:
site:www.runoob.com
file.js
var fs = require("fs");
var buf = new Buffer.alloc(1024);
console.log("準(zhǔn)備打開(kāi)文件!");
fs.open('input.txt', 'r+', function(err, fd) {
if (err) {
return console.error(err);
}
console.log("文件打開(kāi)成功!");
console.log("截取10字節(jié)內(nèi)的文件內(nèi)容,超出部分將被去除。");
// 截取文件
fs.ftruncate(fd, 10, function(err){
if (err){
console.log(err);
}
console.log("文件截取成功。");
console.log("讀取相同的文件");
fs.read(fd, buf, 0, buf.length, 0, function(err, bytes){
if (err){
console.log(err);
}
// 僅輸出讀取的字節(jié)
if(bytes > 0){
console.log(buf.slice(0, bytes).toString());
}
// 關(guān)閉文件
fs.close(fd, function(err){
if (err){
console.log(err);
}
console.log("文件關(guān)閉成功!");
});
});
});
});
刪除文件
語(yǔ)法
fs.unlink(path, callback)
參數(shù)
path - 文件路徑。 callback - 回調(diào)函數(shù),沒(méi)有參數(shù)。
實(shí)例 file.js
var fs = require("fs");
console.log("準(zhǔn)備刪除文件!");
fs.unlink('input.txt', function(err) {
if (err) {
return console.error(err);
}
console.log("文件刪除成功!");
});
創(chuàng)建目錄
語(yǔ)法
fs.mkdir(path[, options], callback)
參數(shù)
path - 文件路徑。 options 參數(shù)可以是:
recursive - 是否以遞歸的方式創(chuàng)建目錄,默認(rèn)為 false。mode - 設(shè)置目錄權(quán)限,默認(rèn)為 0777。 callback - 回調(diào)函數(shù),沒(méi)有參數(shù)。
實(shí)例 file.js
var fs = require("fs");
// tmp 目錄必須存在
console.log("創(chuàng)建目錄 /tmp/test/");
fs.mkdir("./tmp/test/",function(err){
if (err) {
return console.error(err);
}
console.log("目錄創(chuàng)建成功。");
});
讀取目錄
語(yǔ)法
fs.readdir(path, callback)
參數(shù)
path - 文件路徑。callback - 回調(diào)函數(shù),回調(diào)函數(shù)帶有兩個(gè)參數(shù)err, files,err 為錯(cuò)誤信息,files 為 目錄下的文件數(shù)組列表。
實(shí)例 file.js
var fs = require("fs");
console.log("查看 /tmp 目錄");
fs.readdir("/tmp/",function(err, files){
if (err) {
return console.error(err);
}
files.forEach( function (file){
console.log( file );
});
});
刪除目錄
語(yǔ)法
fs.rmdir(path, callback)
參數(shù)
path - 文件路徑。callback - 回調(diào)函數(shù),沒(méi)有參數(shù)。
實(shí)例 file.js
var fs = require("fs");
// 執(zhí)行前創(chuàng)建一個(gè)空的 /tmp/test 目錄
console.log("準(zhǔn)備刪除目錄 /tmp/test");
fs.rmdir("/tmp/test",function(err){
if (err) {
return console.error(err);
}
console.log("讀取 /tmp 目錄");
fs.readdir("/tmp/",function(err, files){
if (err) {
return console.error(err);
}
files.forEach( function (file){
console.log( file );
});
});
});
GET/POST 請(qǐng)求
在很多場(chǎng)景中,我們的服務(wù)器都需要跟用戶(hù)的瀏覽器打交道,如表單提交。
表單提交到服務(wù)器一般都使用 GET/POST 請(qǐng)求。
獲取 GET 請(qǐng)求內(nèi)容
由于GET請(qǐng)求直接被嵌入在路徑中,URL是完整的請(qǐng)求路徑,包括了?后面的部分,因此你可以手動(dòng)解析后面的內(nèi)容作為GET請(qǐng)求的參數(shù)。
node.js 中 url 模塊中的 parse 函數(shù)提供了這個(gè)功能。
var http = require('http');
var url = require('url');
var util = require('util');
http.createServer(function(req, res){
res.writeHead(200, {'Content-Type': 'text/plain'});
// 解析 url 參數(shù)
var params = url.parse(req.url, true).query;
res.write("網(wǎng)站名:" + params.name);
res.write("\n");
res.write("網(wǎng)站 URL:" + params.url);
res.end();
}).listen(3000);
獲取 POST 請(qǐng)求內(nèi)容
POST 請(qǐng)求的內(nèi)容全部的都在請(qǐng)求體中。
node.js 默認(rèn)是不會(huì)解析請(qǐng)求體的,當(dāng)你需要的時(shí)候,需要手動(dòng)來(lái)做。
var http = require('http');
var querystring = require('querystring');
var util = require('util');
http.createServer(function(req, res){
// 定義了一個(gè)post變量,用于暫存請(qǐng)求體的信息
var post = '';
// 通過(guò)req的data事件監(jiān)聽(tīng)函數(shù),每當(dāng)接受到請(qǐng)求體的數(shù)據(jù),就累加到post變量中
req.on('data', function(chunk){
post += chunk;
});
// 在end事件觸發(fā)后,通過(guò)querystring.parse將post解析為真正的POST請(qǐng)求格式,然后向客戶(hù)端返回。
req.on('end', function(){
post = querystring.parse(post);
res.end(util.inspect(post));
});
}).listen(3000);
Web 模塊
目前最主流的三個(gè)Web服務(wù)器是Apache、Nginx、IIS。
Web 應(yīng)用架構(gòu)
Client - 客戶(hù)端,一般指瀏覽器,瀏覽器可以通過(guò) HTTP 協(xié)議向服務(wù)器請(qǐng)求數(shù)據(jù)。 Server - 服務(wù)端,一般指 Web 服務(wù)器,可以接收客戶(hù)端請(qǐng)求,并向客戶(hù)端發(fā)送響應(yīng)數(shù)據(jù)。 Business - 業(yè)務(wù)層, 通過(guò) Web 服務(wù)器處理應(yīng)用程序,如與數(shù)據(jù)庫(kù)交互,邏輯運(yùn)算,調(diào)用外部程序等。 Data - 數(shù)據(jù)層,一般由數(shù)據(jù)庫(kù)組成。
使用 Node 創(chuàng)建 Web 服務(wù)器
Node.js 提供了 http 模塊,http 模塊主要用于搭建 HTTP 服務(wù)端和客戶(hù)端。
以下是演示一個(gè)最基本的 HTTP 服務(wù)器架構(gòu)(使用 8080 端口),創(chuàng)建server.js文件,代碼如下所示:
var http = require('http');
var fs = require('fs');
var url = require('url');
// 創(chuàng)建服務(wù)器
http.createServer( function (request, response) {
// 解析請(qǐng)求,包括文件名
var pathname = url.parse(request.url).pathname;
// 輸出請(qǐng)求的文件名
console.log("Request for " + pathname + " received.");
// 從文件系統(tǒng)中讀取請(qǐng)求的文件內(nèi)容
fs.readFile(pathname.substr(1), function (err, data) {
if (err) {
console.log(err);
// HTTP 狀態(tài)碼: 404 : NOT FOUND
// Content Type: text/html
response.writeHead(404, {'Content-Type': 'text/html'});
}else{
// HTTP 狀態(tài)碼: 200 : OK
// Content Type: text/html
response.writeHead(200, {'Content-Type': 'text/html'});
// 響應(yīng)文件內(nèi)容
response.write(data.toString());
}
// 發(fā)送響應(yīng)數(shù)據(jù)
response.end();
});
}).listen(8080);
// 控制臺(tái)會(huì)輸出以下信息
console.log('Server running at http://127.0.0.1:8080/');
執(zhí)行 server.js 程序: 打開(kāi)地址:
使用 Node 創(chuàng)建 Web 客戶(hù)端
client.js
var http = require('http');
// 用于請(qǐng)求的選項(xiàng)
var options = {
host: 'localhost',
port: '8080',
path: '/index.html'
};
// 處理響應(yīng)的回調(diào)函數(shù)
var callback = function(response){
// 不斷更新數(shù)據(jù)
var body = '';
response.on('data', function(data) {
body += data;
});
response.on('end', function() {
// 數(shù)據(jù)接收完成
console.log(body);
});
}
// 向服務(wù)端發(fā)送請(qǐng)求
var req = http.request(options, callback);
req.end();
在 server.js 啟動(dòng)的情況下,ctrl + shift + ` 新開(kāi)一個(gè)終端,執(zhí)行 client.js 文件: 客戶(hù)端請(qǐng)求信息,執(zhí)行 server.js 的控制臺(tái)輸出:
Express 框架
使用 Express 可以快速地搭建一個(gè)完整功能的網(wǎng)站。
安裝
cnpm install express
cnpm install body-parser
cnpm install cookie-parser
cnpm install multer
以下幾個(gè)重要的模塊是需要與 express 框架一起安裝的:
body-parser - 用于處理 JSON, Raw, Text 和 URL 編碼的數(shù)據(jù)。 cookie-parser - 這就是一個(gè)解析Cookie的工具。通過(guò)req.cookies可以取到傳過(guò)來(lái)的cookie,并把它們轉(zhuǎn)成對(duì)象。 multer - 用于處理 enctype=“multipart/form-data”(設(shè)置表單的MIME編碼)的表單數(shù)據(jù)。
第一個(gè) Express 框架實(shí)例
以下實(shí)例中我們引入了 express 模塊,并在客戶(hù)端發(fā)起請(qǐng)求后,響應(yīng) “Hello World” 字符串。
創(chuàng)建 express_demo.js 文件,代碼如下所示:
var express = require('express');
var app = express();
app.get('/', function (req, res) {
res.send('Hello World');
})
var server = app.listen(8081, '127.0.0.1',function () {
var host = server.address().address
var port = server.address().port
console.log("應(yīng)用實(shí)例,訪問(wèn)地址為 http://%s:%s", host, port)
})
請(qǐng)求和響應(yīng)
Express 應(yīng)用使用回調(diào)函數(shù)的參數(shù): request 和 response 對(duì)象來(lái)處理請(qǐng)求和響應(yīng)的數(shù)據(jù)。
app.get('/', function (req, res) {
// --
})
Request 對(duì)象 - request 對(duì)象表示 HTTP 請(qǐng)求,包含了請(qǐng)求查詢(xún)字符串,參數(shù),內(nèi)容,HTTP 頭部等屬性。Response 對(duì)象 - response 對(duì)象表示 HTTP 響應(yīng),即在接收到請(qǐng)求時(shí)向客戶(hù)端發(fā)送的 HTTP 響應(yīng)數(shù)據(jù)。
路由
路由決定了由誰(shuí)(指定腳本)去響應(yīng)客戶(hù)端請(qǐng)求。
在HTTP請(qǐng)求中,我們可以通過(guò)路由提取出請(qǐng)求的URL以及GET/POST參數(shù)。
express_demo2.js
var express = require('express');
var app = express();
// 主頁(yè)輸出 "Hello World"
app.get('/', function (req, res) {
console.log("主頁(yè) GET 請(qǐng)求");
res.send('Hello GET');
})
// POST 請(qǐng)求
app.post('/', function (req, res) {
console.log("主頁(yè) POST 請(qǐng)求");
res.send('Hello POST');
})
// /del_user 頁(yè)面響應(yīng)
app.get('/del_user', function (req, res) {
console.log("/del_user 響應(yīng) DELETE 請(qǐng)求");
res.send('刪除頁(yè)面');
})
// /list_user 頁(yè)面 GET 請(qǐng)求
app.get('/list_user', function (req, res) {
console.log("/list_user GET 請(qǐng)求");
res.send('用戶(hù)列表頁(yè)面');
})
// 對(duì)頁(yè)面 abcd, abxcd, ab123cd, 等響應(yīng) GET 請(qǐng)求
app.get('/ab*cd', function(req, res) {
console.log("/ab*cd GET 請(qǐng)求");
res.send('正則匹配');
})
var server = app.listen(8081,'127.0.0.1',function () {
var host = server.address().address
var port = server.address().port
console.log("應(yīng)用實(shí)例,訪問(wèn)地址為 http://%s:%s", host, port)
})
靜態(tài)文件
你可以使用express.static中間件來(lái)設(shè)置靜態(tài)文件路徑。例如,如果你將圖片, CSS, JavaScript 文件放在 public 目錄下,你可以這么寫(xiě):
app.use('/public', express.static('public'));
創(chuàng)建文件夾public/images,放入圖片logo.png express_demo3.js
var express = require('express');
var app = express();
app.use('/public', express.static('public'));
app.get('/', function (req, res) {
res.send('Hello World');
})
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("應(yīng)用實(shí)例,訪問(wèn)地址為 http://%s:%s", host, port)
})
訪問(wèn)網(wǎng)頁(yè):http://127.0.0.1:8081/public/images/logo.png
得到logo.png:
GET 方法
在表單中通過(guò) GET 方法提交兩個(gè)參數(shù),我們可以使用 server.js 文件內(nèi)的 process_get 路由器來(lái)處理輸入:
index.html 文件代碼:
server.js 文件代碼:
var express = require('express');
var app = express();
app.use('/public', express.static('public'));
app.get('/index.html', function (req, res) {
res.sendFile( __dirname + "/" + "index.html" );
})
app.get('/process_get', function (req, res) {
// 輸出 JSON 格式
var response = {
"first_name":req.query.first_name,
"last_name":req.query.last_name
};
console.log(response);
res.end(JSON.stringify(response));
})
var server = app.listen(8081,'127.0.0.1',function () {
var host = server.address().address
var port = server.address().port
console.log("應(yīng)用實(shí)例,訪問(wèn)地址為 http://%s:%s", host, port)
})
POST 方法
在表單中通過(guò) POST 方法提交兩個(gè)參數(shù),我們可以使用 server.js 文件內(nèi)的 process_post 路由器來(lái)處理輸入:
index.html 文件代碼:
server.js 文件代碼:
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
// 創(chuàng)建 application/x-www-form-urlencoded 編碼解析
var urlencodedParser = bodyParser.urlencoded({ extended: false })
app.use('/public', express.static('public'));
app.get('/index.html', function (req, res) {
res.sendFile( __dirname + "/" + "index.html" );
})
app.post('/process_post', urlencodedParser, function (req, res) {
// 輸出 JSON 格式
var response = {
"first_name":req.body.first_name,
"last_name":req.body.last_name
};
console.log(response);
res.end(JSON.stringify(response));
})
var server = app.listen(8081,'127.0.0.1',function () {
var host = server.address().address
var port = server.address().port
console.log("應(yīng)用實(shí)例,訪問(wèn)地址為 http://%s:%s", host, port)
})
文件上傳
創(chuàng)建一個(gè)用于上傳文件的表單,使用 POST 方法,表單 enctype 屬性設(shè)置為 multipart/form-data。
index.html 文件代碼:
文件上傳:
選擇一個(gè)文件上傳:
server.js 文件代碼:
var express = require('express');
var app = express();
var fs = require("fs");
var bodyParser = require('body-parser');
var multer = require('multer');
app.use('/public', express.static('public'));
app.use(bodyParser.urlencoded({ extended: false }));
app.use(multer({ dest: '/tmp/'}).array('image'));
app.get('/index.html', function (req, res) {
res.sendFile( __dirname + "/" + "index.html" );
})
app.post('/file_upload', function (req, res) {
console.log(req.files[0]); // 上傳的文件信息
var des_file = __dirname + "/" + req.files[0].originalname;
fs.readFile( req.files[0].path, function (err, data) {
fs.writeFile(des_file, data, function (err) {
if( err ){
console.log( err );
}else{
response = {
message:'File uploaded successfully',
filename:req.files[0].originalname
};
}
console.log( response );
res.end( JSON.stringify( response ) );
});
});
})
var server = app.listen(8081,'127.0.0.1',function () {
var host = server.address().address
var port = server.address().port
console.log("應(yīng)用實(shí)例,訪問(wèn)地址為 http://%s:%s", host, port)
})
Cookie 管理
使用中間件向 Node.js 服務(wù)器發(fā)送 cookie 信息,以下代碼輸出了客戶(hù)端發(fā)送的 cookie 信息: express_cookie.js 文件代碼:
// express_cookie.js 文件
var express = require('express')
var cookieParser = require('cookie-parser')
var util = require('util');
var app = express()
app.use(cookieParser())
app.get('/', function(req, res) {
console.log("Cookies: " + util.inspect(req.cookies));
})
app.listen(8081)
訪問(wèn) http://127.0.0.1:8081,并查看終端信息:
RESTful API
REST即表述性狀態(tài)傳遞(英文:Representational State Transfer)。
REST 通常使用 JSON 數(shù)據(jù)格式。
以下為 REST 基本架構(gòu)的四個(gè)方法:
GET - 用于獲取數(shù)據(jù)。 PUT - 用于更新或添加數(shù)據(jù)。 DELETE - 用于刪除數(shù)據(jù)。 POST - 用于添加數(shù)據(jù)。
創(chuàng)建 RESTful
首先,創(chuàng)建一個(gè) json 數(shù)據(jù)資源文件 users.json:
{
"user1" : {
"name" : "mahesh",
"password" : "password1",
"profession" : "teacher",
"id": 1
},
"user2" : {
"name" : "suresh",
"password" : "password2",
"profession" : "librarian",
"id": 2
},
"user3" : {
"name" : "ramesh",
"password" : "password3",
"profession" : "clerk",
"id": 3
}
}
獲取用戶(hù)列表:
以下代碼,我們創(chuàng)建了 RESTful API listUsers,用于讀取用戶(hù)的信息列表, server.js 文件代碼如下所示:
var express = require('express');
var app = express();
var fs = require("fs");
app.get('/listUsers', function (req, res) {
fs.readFile( __dirname + "/" + "users.json", 'utf8', function (err, data) {
console.log( data );
res.end( data );
});
})
var server = app.listen(8081,'127.0.0.1',function () {
var host = server.address().address
var port = server.address().port
console.log("應(yīng)用實(shí)例,訪問(wèn)地址為 http://%s:%s", host, port)
})
在瀏覽器中訪問(wèn) http://127.0.0.1:8081/listUsers,結(jié)果如下所示:
添加用戶(hù)
以下代碼,我們創(chuàng)建了 RESTful API addUser, 用于添加新的用戶(hù)數(shù)據(jù),server.js 文件代碼如下所示:
var express = require('express');
var app = express();
var fs = require("fs");
//添加的新用戶(hù)數(shù)據(jù)
var user = {
"user4" : {
"name" : "mohit",
"password" : "password4",
"profession" : "teacher",
"id": 4
}
}
app.get('/addUser', function (req, res) {
// 讀取已存在的數(shù)據(jù)
fs.readFile( __dirname + "/" + "users.json", 'utf8', function (err, data) {
data = JSON.parse( data );
data["user4"] = user["user4"];
console.log( data );
res.end( JSON.stringify(data));
});
})
var server = app.listen(8081,'127.0.0.1',function () {
var host = server.address().address
var port = server.address().port
console.log("應(yīng)用實(shí)例,訪問(wèn)地址為 http://%s:%s", host, port)
})
顯示用戶(hù)詳情
我們創(chuàng)建了 RESTful API :id(用戶(hù)id), 用于讀取指定用戶(hù)的詳細(xì)信息,server.js 文件代碼如下所示:
var express = require('express');
var app = express();
var fs = require("fs");
app.get('/:id', function (req, res) {
// 首先我們讀取已存在的用戶(hù)
fs.readFile( __dirname + "/" + "users.json", 'utf8', function (err, data) {
data = JSON.parse( data );
var user = data["user" + req.params.id]
console.log( user );
res.end( JSON.stringify(user));
});
})
var server = app.listen(8081,'127.0.0.1',function () {
var host = server.address().address
var port = server.address().port
console.log("應(yīng)用實(shí)例,訪問(wèn)地址為 http://%s:%s", host, port)
})
刪除用戶(hù)
我們創(chuàng)建了 RESTful API deleteUser, 用于刪除指定用戶(hù)的詳細(xì)信息,以下實(shí)例中,用戶(hù) id 為 2,server.js 文件代碼如下所示:
var express = require('express');
var app = express();
var fs = require("fs");
var id = 2;
app.get('/deleteUser', function (req, res) {
// First read existing users.
fs.readFile( __dirname + "/" + "users.json", 'utf8', function (err, data) {
data = JSON.parse( data );
delete data["user" + id];
console.log( data );
res.end( JSON.stringify(data));
});
})
var server = app.listen(8081,'127.0.0.1',function () {
var host = server.address().address
var port = server.address().port
console.log("應(yīng)用實(shí)例,訪問(wèn)地址為 http://%s:%s", host, port)
})
多進(jìn)程
Node 提供了 child_process 模塊來(lái)創(chuàng)建子進(jìn)程,方法有:
exec() 方法
讓我們創(chuàng)建兩個(gè) js 文件 support.js 和 master.js。
support.js 文件代碼:
console.log("進(jìn)程 " + process.argv[2] + " 執(zhí)行。" );
master.js 文件代碼:
const fs = require('fs');
const child_process = require('child_process');
for(var i=0; i<3; i++) {
var workerProcess = child_process.exec('node support.js '+i, function (error, stdout, stderr) {
if (error) {
console.log(error.stack);
console.log('Error code: '+error.code);
console.log('Signal received: '+error.signal);
}
console.log('stdout: ' + stdout);
console.log('stderr: ' + stderr);
});
workerProcess.on('exit', function (code) {
console.log('子進(jìn)程已退出,退出碼 '+code);
});
}
柚子快報(bào)激活碼778899分享:Node.js---菜鳥(niǎo)教程
好文鏈接
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場(chǎng)。
轉(zhuǎn)載請(qǐng)注明,如有侵權(quán),聯(lián)系刪除。