Node.js 开发实用指南与对象属性配置解析
1. Node.js 文件系统操作
在 Node.js 里,文件系统操作存在同步和异步两种版本。同步版本借助异常处理错误,为让示例更健壮,可将其包裹于
try/catch
块中。例如:
try {
fs.writeFileSync(path.join(__dirname, 'hello.txt'), 'hello from Node!');
} catch(err) {
console.error('Error writing file.');
}
同步文件系统函数使用起来较为简便,但在编写 Web 服务器或网络应用时,要牢记 Node 的性能源于异步执行,此时应始终使用异步版本。若编写命令行工具,使用同步版本通常没问题。
可运用
fs.readdir
列出目录中的文件,示例代码如下:
const fs = require('fs');
fs.readdir(__dirname, function(err, files) {
if(err) return console.error('Unable to read directory contents');
console.log(`Contents of ${__dirname}:`);
console.log(files.map(f => '\t' + f).join('\n'));
});
fs
模块还包含诸多文件系统函数,如下表所示:
| 功能 | 函数 |
| ---- | ---- |
| 删除文件 | fs.unlink |
| 移动或重命名文件 | fs.rename |
| 获取文件和目录信息 | fs.stat |
2. Process 对象的使用
每个运行的 Node 程序都能访问
process
变量,借此获取自身执行信息并加以控制。
2.1 退出程序
若应用遭遇严重错误,不适宜或无意义继续执行(即致命错误),可调用
process.exit
立即停止执行,还能提供数字退出码,脚本会依据此码判断程序是否成功退出。惯例上,退出码 0 表示“无错误”,非零退出码表示有错误。示例如下:
const fs = require('fs');
fs.readdir('data', function(err, files) {
if(err) {
console.error("Fatal error: couldn't read data directory.");
process.exit(1);
}
const txtFiles = files.filter(f => /\.txt$/i.test(f));
if(txtFiles.length === 0) {
console.log("No .txt files to process.");
process.exit(0);
}
// process .txt files...
});
2.2 命令行参数
process.argv
数组包含传递给程序的命令行参数。例如,编写一个统计文件行数的程序:
const fs = require('fs');
const filenames = process.argv.slice(2);
let counts = filenames.map(f => {
try {
const data = fs.readFileSync(f, { encoding: 'utf8' });
return `${f}: ${data.split('\n').length}`;
} catch(err) {
return `${f}: couldn't read file`;
}
});
console.log(counts.join('\n'));
2.3 环境变量
通过
process.env
对象可访问环境变量,环境变量常用于配置程序的某些行为。例如,使用
DEBUG
环境变量控制程序是否输出调试信息:
const debug = process.env.DEBUG === "1" ?
console.log :
function() {};
debug("Visible only if environment variable DEBUG is set!");
2.4 当前工作目录
process.cwd
能告知当前工作目录,
process.chdir
可更改当前工作目录。示例如下:
console.log(`Current directory: ${process.cwd()}`);
process.chdir(__dirname);
console.log(`New current directory: ${process.cwd()}`);
3. 操作系统信息获取
os
模块可提供运行应用的计算机的特定平台信息,示例代码如下:
const os = require('os');
console.log("Hostname: " + os.hostname()); // prometheus
console.log("OS type: " + os.type()); // Linux
console.log("OS platform: " + os.platform()); // linux
console.log("OS release: " + os.release()); // 3.13.0-52-generic
console.log("OS uptime: " +
(os.uptime()/60/60/24).toFixed(1) + " days"); // 80.3 days
console.log("CPU architecture: " + os.arch()); // x64
console.log("Number of CPUs: " + os.cpus().length); // 1
console.log("Total memory: " +
(os.totalmem()/1e6).toFixed(1) + " MB"); // 1042.3 MB
console.log("Free memory: " +
(os.freemem()/1e6).toFixed(1) + " MB"); // 195.8 MB
4. 子进程管理
child_process
模块可让应用运行其他程序,该模块暴露了三个主要函数:
exec
、
execFile
和
fork
,同时也有对应的同步版本。
4.1 函数特点
-
exec:调用 shell 执行命令,若能在命令行运行的命令,就能用exec运行。 -
execFile:直接执行可执行文件,内存和资源使用稍优,但通常需更谨慎使用。 -
fork:用于执行其他 Node 脚本,会调用单独的 Node 引擎,不过能提供一些进程间通信选项。
4.2 示例代码
使用
exec
执行
dir
命令:
const exec = require('child_process').exec;
exec('dir', function(err, stdout, stderr) {
if(err) return console.error('Error executing "dir"');
stdout = stdout.toString(); // convert Buffer to string
console.log(stdout);
stderr = stderr.toString();
if(stderr !== '') {
console.error('error:');
console.error(stderr);
}
});
5. 流的使用
在 Node 中,流是处理数据的重要概念。流可分为读取流、写入流和双工流。
5.1 写入流
创建并使用写入流的示例:
const ws = fs.createWriteStream('stream.txt', { encoding: 'utf8' });
ws.write('line 1\n');
ws.write('line 2\n');
ws.end();
5.2 读取流
创建并使用读取流的示例:
const rs = fs.createReadStream('stream.txt', { encoding: 'utf8' });
rs.on('data', function(data) {
console.log('>> data: ' + data.replace('\n', '\\n'));
});
rs.on('end', function(data) {
console.log('>> end');
});
5.3 流的管道操作
使用管道操作将一个文件的内容复制到另一个文件:
const rs = fs.createReadStream('stream.txt');
const ws = fs.createWriteStream('stream_copy.txt');
rs.pipe(ws);
6. Web 服务器搭建
Node 最初的用途是提供 Web 服务器,借助
http
模块的
createServer
方法可轻松创建基本 Web 服务器。示例代码如下:
const http = require('http');
const server = http.createServer(function(req, res) {
console.log(`${req.method} ${req.url}`);
res.end('Hello world!');
});
const port = 8080;
server.listen(port, function() {
console.log(`server startd on port ${port}`);
});
大多数操作系统出于安全考虑,不允许无提升权限监听默认 HTTP 端口(80),开发和测试时通常监听 1024 以上的端口。
当访问
http://localhost:8080
时,会看到
Hello world!
,同时控制台会记录请求信息,可能会看到两个请求:
GET /
GET /favicon.ico
这是因为大多数浏览器会隐式请求一个图标用于显示在 URL 栏或标签中。
6.1 处理特定请求
若有
favicon.ico
文件,可直接响应此请求:
const server = http.createServer(function(req, res) {
if(req.method === 'GET' && req.url === '/favicon.ico') {
const fs = require('fs');
fs.createReadStream('favicon.ico');
fs.pipe(res); // this replaces the call to 'end'
} else {
console.log(`${req.method} ${req.url}`);
res.end('Hello world!');
}
});
7. 对象属性配置与代理
7.1 访问器属性
对象属性分为数据属性和访问器属性。访问器属性有 getter 和 setter 两个函数,访问时更像数据属性而非函数。
7.2 示例代码
传统方式定义
User
类:
const USER_EMAIL = Symbol();
class User {
setEmail(value) {
if(!/@/.test(value)) throw new Error(`invalid email: ${value}`);
this[USER_EMAIL] = value;
}
getEmail() {
return this[USER_EMAIL];
}
}
const u = new User();
u.setEmail("john@doe.com");
console.log(`User email: ${u.getEmail()}`);
使用访问器属性重写
User
类:
const USER_EMAIL = Symbol();
class User {
set email(value) {
if(!/@/.test(value)) throw new Error(`invalid email: ${value}`);
this[USER_EMAIL] = value;
}
get email() {
return this[USER_EMAIL];
}
}
const u = new User();
u.email = "john@doe.com";
console.log(`User email: ${u.email}`);
7.3 只读属性示例
定义一个计算矩形周长的只读属性:
class Rectangle {
constructor(width, height) {
this.width = width;
this.height = height;
}
get perimeter() {
return this.width*2 + this.height*2;
}
}
综上所述,本文详细介绍了 Node.js 的文件系统操作、
process
对象、操作系统信息获取、子进程管理、流的使用、Web 服务器搭建以及对象属性配置等方面的知识,并给出了丰富的代码示例,希望能帮助读者更好地掌握 Node.js 开发。
8. 技术总结与流程梳理
8.1 关键技术总结
| 技术模块 | 核心功能 | 关键函数/方法 |
|---|---|---|
| 文件系统操作 | 同步和异步文件读写、目录读取等 |
fs.writeFileSync
、
fs.readdir
、
fs.unlink
、
fs.rename
、
fs.stat
|
| Process 对象 | 程序退出控制、获取命令行参数和环境变量、管理当前工作目录 |
process.exit
、
process.argv
、
process.env
、
process.cwd
、
process.chdir
|
| 操作系统信息获取 | 获取计算机平台相关信息 |
os.hostname
、
os.type
、
os.platform
、
os.release
、
os.uptime
、
os.arch
、
os.cpus
、
os.totalmem
、
os.freemem
|
| 子进程管理 | 运行其他程序 |
exec
、
execFile
、
fork
|
| 流的使用 | 数据读写和传输 |
fs.createWriteStream
、
fs.createReadStream
、
rs.pipe
|
| Web 服务器搭建 | 创建基本 Web 服务器并处理请求 |
http.createServer
、
server.listen
|
| 对象属性配置 | 定义和使用访问器属性 |
get
、
set
|
8.2 流程梳理 - Web 服务器请求处理流程
graph TD;
A[客户端发起请求] --> B[服务器接收请求];
B --> C{判断请求类型和 URL};
C -- GET / --> D[记录请求信息并返回 'Hello world!'];
C -- GET /favicon.ico --> E[读取 favicon.ico 文件并返回];
D --> F[响应结束];
E --> F;
9. 操作步骤详解
9.1 创建 Web 服务器详细步骤
-
引入
http模块 :
const http = require('http');
- 创建服务器实例 :
const server = http.createServer(function(req, res) {
// 处理请求逻辑
console.log(`${req.method} ${req.url}`);
if(req.method === 'GET' && req.url === '/favicon.ico') {
const fs = require('fs');
fs.createReadStream('favicon.ico').pipe(res);
} else {
res.end('Hello world!');
}
});
- 指定服务器监听端口 :
const port = 8080;
server.listen(port, function() {
console.log(`server startd on port ${port}`);
});
9.2 使用流复制文件详细步骤
- 创建读取流 :
const rs = fs.createReadStream('stream.txt');
- 创建写入流 :
const ws = fs.createWriteStream('stream_copy.txt');
- 使用管道操作复制文件 :
rs.pipe(ws);
10. 常见问题与解决方法
10.1 文件操作错误处理
在进行文件操作时,可能会遇到文件不存在、权限不足等错误。可使用
try/catch
块捕获同步操作的错误,异步操作则在回调函数中处理错误。
// 同步操作错误处理
try {
fs.writeFileSync('nonexistent/path/hello.txt', 'hello from Node!');
} catch(err) {
console.error('Error writing file:', err.message);
}
// 异步操作错误处理
fs.readdir('nonexistent/dir', function(err, files) {
if(err) {
console.error('Error reading directory:', err.message);
} else {
// 处理文件列表
}
});
10.2 Web 服务器端口占用问题
若指定的端口已被其他程序占用,服务器将无法启动。可尝试更换端口,如将
port
改为其他未被使用的端口。
const port = 8081; // 更换端口
server.listen(port, function() {
console.log(`server startd on port ${port}`);
});
11. 综合示例 - 带环境变量配置的文件行数统计程序
11.1 需求说明
编写一个程序,接收多个文件名作为命令行参数,统计每个文件的行数,并根据环境变量
DEBUG
控制是否输出调试信息。
11.2 代码实现
const fs = require('fs');
const filenames = process.argv.slice(2);
const debug = process.env.DEBUG === "1" ? console.log : function() {};
debug('Starting line count program...');
let counts = filenames.map(f => {
try {
const data = fs.readFileSync(f, { encoding: 'utf8' });
return `${f}: ${data.split('\n').length}`;
} catch(err) {
return `${f}: couldn't read file`;
}
});
console.log(counts.join('\n'));
debug('Line count program finished.');
11.3 运行步骤
- 正常运行(不输出调试信息) :
node linecount.js file1.txt file2.txt
- 开启调试信息输出 :
# Unix 系统
export DEBUG=1
node linecount.js file1.txt file2.txt
# Windows 系统
set DEBUG=1
node linecount.js file1.txt file2.txt
12. 总结与展望
12.1 总结
本文全面介绍了 Node.js 开发中的多个重要方面,包括文件系统操作、
process
对象、操作系统信息获取、子进程管理、流的使用、Web 服务器搭建以及对象属性配置等知识。通过丰富的代码示例和详细的操作步骤,帮助读者深入理解和掌握这些技术的使用方法。
12.2 展望
Node.js 作为一个强大的 JavaScript 运行环境,在 Web 开发、服务器端编程等领域有着广泛的应用前景。未来,随着技术的不断发展,Node.js 可能会在性能优化、功能扩展等方面取得更大的突破。例如,可能会出现更高效的异步处理机制、更便捷的模块管理方式等。同时,Node.js 与其他技术的结合也将更加紧密,如与前端框架 React、Vue.js 等的集成,为开发者提供更完整的开发解决方案。
希望读者通过本文的学习,能够在实际项目中灵活运用这些技术,提高开发效率和代码质量。在后续的学习和实践中,不断探索和发现 Node.js 的更多可能性。
超级会员免费看
1436

被折叠的 条评论
为什么被折叠?



