NodeJS
是什么?
简单的说Node.js
就是运行在服务端的JavaScript
。
Node.js
是一个基于ChromeV8
引擎的JavaScript
运行时。Node.js
使用高效、轻量级的事件驱动、非阻塞I/O
模型。与前端的不同
JS
核心语法不变
前端BOM DOM
后端fs http buffer event os
-
运行
node
程序
node 01-runnode.js
每次修改js
文件需重新执行才能生效,安装nodemon
可以watch
文件改动,自动重启。npm i -g nodemon nodemon 01-runnode.js
调试
node
程序:Debug - Start Debugging
-
模块
module
// node内建模块 const os = require('os') const mem= (os.freemem() / os.totalmem()) * 100 console.log(`内存占用率${mem}%`) // 第三方模块 const cpuStat = require('cpu-stat') cpuStat.usagePercent((err, percent) => console.log(`CPU占用:${percent.toFixed(2)}%`)) // 回调方法 const util = require('util') const getCpu = util.promisify(cpuStat.usagePercent) getCpu().then(percent => { console.log(`CPU占用:${percent.toFixed(2)}%`) }) //加入定时器定时显示统计 const showStat = async () => { const mem = (os.freemem() / os.totalmem()) * 100 const percent = await getCpu() console.log(`CPU占用:${percent.toFixed(2)}% 内存: ${mem} %`) } setInterval(showStat, 1000) // 自定义模块 // currency.js // 保存汇率 let rate; function rmbToDollar(rmb) { return rmb / rate; } function dollarToRmb(dollar) { return dollar * rate; } module.exports = function (r) { rate = r; return { rmbToDollar, dollarToRmb }; }; const { rmbToDollar, dollarToRmb } = require('./currency')(6) console.log(rmbToDollar(10), dollarToRmb(10))
-
核心
API
- fs:文件系统
// fs - 文件系统 const fs = require('fs'); // 同步调用 const data = fs.readFileSync('./currency.js'); // 代码会阻塞在这里 // 下面是同步调用,实际中建议使用异步版本 fs.readFile('./currency.js', (err, data) => { if (err) throw err; console.log(data); }); // fs常常搭配path api使用 const path = require('path') fs.readFile(path.resolve(__dirname, './currency.js'), (err, data) => { if (err) throw err; console.log(data); }); // 异步调用 // promisify const { promisify } = require('util') const readFile = promisify(fs.readFile) readFile('./currency.js').then(data => console.log(data)) // Promises const fsp = require('fs').promises; fsp .readFile('./currency.js') .then(data => console.log(data)) .catch(err => console.log(err)); // async/await (async () => { const fs = require('fs') const { promisify } = require('util') const readFile = promisify(fs.readFile) const data = await readFile('./currency.js') console.log('data', data) })()
- Buffer:用于在
TCP
流、文件系统操作、以及其他上下文中与八位字节流进行交互。 八位字节组成的数组,可以有效的在JS
中存储二进制数据
Buffer.from(data).toString('utf-8') // 创建一个长度为10字节以0填充的Buffer const buf1 = Buffer.alloc(10); console.log(buf1); // 创建一个Buffer包含ascii const buf2 = Buffer.from('a') console.log(buf2, buf2.toString()) // 创建Buffer包含UTF-8字节 const buf3 = Buffer.from('Buffer创建方法'); console.log(buf3); // 写入Buffer数据 buf1.write('hello'); console.log(buf1); // 读取Buffer数据 console.log(buf3.toString()); // 合并Buffer const buf4 = Buffer.concat([buf1, buf3]); console.log(buf4.toString());
- http:用于创建
web
服务的模块
// localhost:3000 const http = require('http'); const server = http.createServer((request, response) => { console.log('there is a request'); response.end('a response from server'); }); server.listen(3000); const http = require('http'); const fs = require('fs'); http.createServer((request, response) => { const { url, method } = request; // 返回html,http://localhost:3000 if (url === '/' && method === 'GET') { fs.readFile('index.html', (err, data) => { if (err) { response.writeHead(500, { 'Content-Type': 'text/plain;charset=utf8' }); response.end('500,服务器错误'); return ; } response.statusCode = 200; response.setHeader('Content-Type', 'text/html'); response.end(data); }); } else { response.statusCode = 404; response.setHeader('Content-Type', 'text/plain;charset=utf-8'); response.end('404, 页面没有找到'); } // 实现接口 // http://localhost:3000/users // if (url === '/users' && method === 'GET') { // response.writeHead(200, { 'Content-Type': 'application/json' }); // response.end(JSON.stringify({ code: 0, data: [{name:'tom',age:20}], message: 'success'})); // } }).listen(3000); // 打印原型链 function getPrototypeChain(object) { let protoChain = []; // Object.getPrototypeOf() 方法返回指定对象的原型 while (object = Object.getPrototypeOf(object)) { protoChain.push(object); } protoChain.push(null); return protoChain; } console.log(getPrototypeChain(new String(''))) // [ [String: ''], {}, null ] console.log(getPrototypeChain(function(){})) // [Function], {}, null ]
- stream:是用于与
node
中流数据交互的接口
const fs = require('fs') /* createReadStream(path, option): 用来打开一个可读的文件流,返回一个fs.ReadStream对象 @params: path 指定文件的路径 @params: options 可选,是一个JS对象,可以指定一些选项如: let option = { flags: 'r', // 指定用什么模式打开文件,’w’代表写,’r’代表读,类似的还有’r+’、’w+’、’a’等 encoding: 'utf8', // 指定打开文件时使用编码格式,默认就是“utf8”,你还可以为它指定”ascii”或”base64” fd: null, // fd属性默认为null,当你指定了这个属性时,createReadableStream会根据传入的fd创建一个流,忽略path。另外你要是想读取一个文件的特定区域,可以配置start、end属性,指定起始和结束(包含在内)的字节偏移 mode: 0666, autoClose: true // autoClose属性为true(默认行为)时,当发生错误或文件读取结束时会自动关闭文件描述符 } */ // 读取文件 let readStream = fs.createReadStream('./01-useModule.js', { encoding: 'utf8' }); // 读取文件发生错误事件 readStream.on('error', (err) => { console.log('发生异常:', err); }); // 已打开要读取的文件事件 readStream.on('open', (fd) => { console.log('文件已打开:', fd); }); // 文件已经就位,可用于读取事件 readStream.on('ready', () => { console.log('文件已准备好...'); }); // 文件读取中事件 readStream.on('data', (chunk) => { console.log('读取文件数据:', chunk); }); // 文件读取完成事件 readStream.on('end', () => { console.log('读取已完成...'); }); // 文件已关闭事件 readStream.on('close', () => { console.log('文件已关闭!'); }); /* createWriteStream():对文件流进行写入 @params: path 指定文件的路径 @params: options 可选,是一个JS对象,可以指定一些选项如: let option = { flags: 'w', // 指定用什么模式打开文件,’w’代表写,’r’代表读,类似的还有’r+’、’w+’、’a’等 encoding: 'utf8', // 指定打开文件时使用编码格式,默认就是“utf8”,你还可以为它指定”ascii”或”base64” fd: null, // fd属性默认为null,当你指定了这个属性时,createReadableStream会根据传入的fd创建一个流,忽略path。另外你要是想读取一个文件的特定区域,可以配置start、end属性,指定起始和结束(包含在内)的字节偏移 mode: 0666, autoClose: true // autoClose属性为true(默认行为)时,当发生错误或文件读取结束时会自动关闭文件描述符 } */ let writeStream = fs.createWriteStream('./index.html', { encoding: 'utf8' }); // 读取文件发生错误事件 writeStream.on('error', (err) => { console.log('发生异常:', err); }); // 已打开要写入的文件事件 writeStream.on('open', (fd) => { console.log('文件已打开:', fd); }); // 文件已经就写入完成事件 writeStream.on('finish', () => { console.log('写入已完成...'); }); // 文件关闭事件 writeStream.on('close', () => { console.log('文件已关闭!'); }); writeStream.write(fs.readFileSync('./02-fs.js', 'utf8')); writeStream.end();
仿写一个简版
Express
// my-espress.js
const http = require('http')
const url = require('url')
const router = []
class Application {
get(path, handler) {
if (typeof path === 'string') {
router.push({
path,
method: 'get',
handler
})
}
}
listen() {
const server = http.createServer((req, res) => {
const { pathname } = url.parse(req.url, true)
for (const route of router) {
const { path, method, handler } = route
if (pathname == path && req.method.toLowerCase() == method) {
return handler(req, res)
}
}
})
server.listen(...arguments)
}
}
module.exports = function createApplication() {
return new Application()
}
// const express = require('express');
// const app = express();
const myExpress = require('./my-espress');
const app = myExpress();
app.get('/', (req, res) => {
res.end('Hello World');
});
app.get('/users', (req, res) => {
res.end(JSON.stringify([{ name: 'tom', age: 20 }]));
});
app.listen(3000, () => {
console.log('Example app listen at 3000');
});
- 事件
event
const { EventEmitter } = require('events')
const event = new EventEmitter()
// 监听器 #1
const listener1 = function listener1() {
console.log('监听器 listener1 执行。');
}
// 监听器 #2
const listener2 = function listener2() {
console.log('监听器 listener2 执行。');
}
// 绑定 connection 事件,处理函数为 listener1
event.addListener('connection', listener1);
// 绑定 connection 事件,处理函数为 listener2
event.on('connection', listener2);
// 为指定事件注册一个单次监听器,即 监听器最多只会触发一次,触发后立刻解除该监听器
event.once('onceconnection', () => console.log('onceconnection'));
// 返回指定事件的监听器数量
let eventListeners = event.listenerCount('connection');
console.log(eventListeners + ' 个监听器监听连接事件。');
// 按监听器的顺序执行执行每个监听器,如果事件有注册监听返回 true,否则返回 false。
// 处理 connection 事件
event.emit('connection');
event.emit('onceconnection');
// 移除指定事件的某个监听器,监听器必须是该事件已经注册过的监听器。需要注意的是,此操作将会改变处于被删监听器之后的那些监听器的索引
// 移除监绑定的 listener1 函数
event.removeListener('connection', listener1);
console.log("listener1 不再受监听。");
// 触发连接事件
event.emit('connection');
eventListeners = event.listenerCount('connection');
console.log(eventListeners + ' 个监听器监听连接事件。');
event.on('customer_event', () => {
console.log('custom...' + new Date())
})
setInterval(() => {
event.emit('customer_event')
}, 1000)