Node.js 基础

  1. NodeJS是什么?
    简单的说Node.js就是运行在服务端的JavaScript
    Node.js是一个基于ChromeV8引擎的JavaScript运行时。Node.js使用高效、轻量级的事件驱动、非阻塞I/O模型。

  2. 与前端的不同
    JS核心语法不变
    前端 BOM DOM
    后端 fs http buffer event os

  3. 运行node程序
    node 01-runnode.js
    每次修改js文件需重新执行才能生效,安装 nodemon可以watch文件改动,自动重启。

    npm i -g nodemon
    nodemon 01-runnode.js
    

    调试node程序:Debug - Start Debugging

  4. 模块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))
    
  5. 核心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();
    
  6. 仿写一个简版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');
});
  1. 事件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)

你可能感兴趣的:(Node.js 基础)