NodeJs是什么

node是一个异步的事件驱动的javascript运行时。即node并不是一门开发语言,而是一个运行环境,让服务器可以识别并运行javascript代码。
node的特点为 非阻塞IO 和 事件驱动 这两点我们再后面会讲到。node 基于v8,并不包含javascript的全局.

在服务端,因为并不存在浏览器环境,也就没有DOM和BOM,所以在node中,只有ECMAScript + 一部分系统操作对象,如fs, buffer, process。

线程,进程

程序的分配单位靠的是进程,也是计算机最小运行单位,进程可以理解为一个环境,环境中可以开很多线程。

node主线程是单线程, 但是底层还是通过多线程来模拟了异步操作。

Java是多线程 (切换执行上下文 切换的很快)这就可能涉及到多个线程操作同一个文件的情况,所以加入锁的概念,当文件处于编辑状态时,其他线程只能等待。node是单线程所以没有锁的概念,但是我们知道,文件操作是比较消耗性能的,所以为了不阻止主线程,所以选择异步线程,要依靠回调函数来解决异步问题。

多进程可以增强稳定性,比如说浏览器,每个窗口都是一个进程,如果共用一个进程,一个页面挂掉,所有窗口都会挂掉。

浏览器

共有两个线程,UI线程,js线程,这两个线程是互斥的,一个执行另一个就要停止
浏览器为什么不是多线程呢,是为了防止同时操作dom。

node执行

同步就是阻塞,异步就是非阻塞

基本用法

新建一个js文件,叫test.js;
在里面输入一段js代码

var name = "yindong";
console.log(name);

打开终端命令行,进入到test.js所在的目录,在命令行执行

node ./test.js

可以看到命令行输出 ”yindong“, 即完成了第一个node文件的运行

模块系统

node的模块分为三种:

  1. 内建模块
  2. 第三方模块
  3. 自定义模块

node中自带的模块,包括fs模块,os模块等

// 内建模块使用需要使用require导入, 模块名称不需要携带路径
const fs = require('fs');
const os = require('os');

第三方模块为个人或组织开发的模块,使用前需要安装,使用方式和内建模块相同

// 安装模块 webpack
npm install webpack -g
// 导入webpack
const webpack = require('webpack');

node支持用户自己定义模块,一般情况下,一个文件就代码一个模块, 模块一般为js后缀名

比如新建一个模块,模块名为conf.js;

var age = 18;
// 导出模块内容,模块中的内容需要导出才可以被载入使用
module.exports = age;

使用该模块

// 导入模块,自定义的模块导入需要写明相对位置,如不写则会识别为内建模块或第三方模块,造成模块无法找到
var conf = require('./conf);
console.log(conf);

全局作用

node存在全局对象global,在node中可以直接访问global,这不同于浏览器,浏览器中并没有global,取而代之的是window

// repl read-eval-print-loop 交互式解析器,

核心API

断言, 如果不符合,会停止程序,并打印错误

const assert = require('assert');
// assert(条件, 一段话)
function sum(a, b) {
  assert(arguments.length === 2,  '必须有两个参数');
  assert(typeof a === 'number',  ‘第一个参数必须是数字’);
}

system 文件处理系统,文件的增删改查

const fs = require('fs');
// 获取文件内容 readFile(文件名, 回调函数)
fs.readFile('2.txt', (err, data) => {
  if(err) {
    console.log(err);
  } else {
    console.log(data); // 二进制文件流
    data.toString(); 将二进制转为文字,只有文本文件可以,图片之类的用之后也看不懂
  }
})
// 写入文件内容
fs.writeFile('3.txt', '文件内容', (err) => {
  if (err) {
    console.log('失败');
  } else {
    console.log('成功')
  }
})

// 复制文件
fs.readFile('1.txt', (err, data) => {
  fs.writeFile('2.txt', data, (err) => {

  })
})

// stream 使用缓冲区复制文件
const rs = fs.createReadStream('./conf.txt');
const ws = fs.createWriteStream('./conf2.txt');
rs.pipe(ws);

帮助js处理二进制,一般和文件系统一起使用

// 创建buffer对象
const buf1 = Buffer.alloc(10);
const buf2 = Buffer.from([1, 2, 3]);
const buf3 = Buffer.from("Buffer创建方法");

// 写入
buf1.write('hello');

// 读取
console.log(buf3.toString());

// 合并
const buf4 = Buffer.concat([buf1, buf3]);

使用c语言写的插件,在node中使用。

多线程

一个程序就是一个进程,一个进程会有多个线程
进程和进程是严格隔离的,拥有独立的执行空间。
同一个进程内的所有线程共享一套空间、代码

  1. 多进程
    成本高,速度慢,安全,进程间通信麻烦,写代码简单。
  2. 多线程
    成本低,速度快,不安全,线程间通信简单,写代码复杂。
    Child_Processes
    Cluster
    Process

获取命令行参数

签名,完成加密算法的

const cryptp = require("crypto");
let obj = cryto.createHash('md5');
obj.update('123');
console.log(obj.digest('hex')); // MD5 32位

系统相关

const os = require('os');
// 获取cpu个数
os.cpus(); 

路径

dirname: 目录; aaa/aa/
basename: 文件名; aaaa.txt
extname: 扩展名 .txt

const path = require('path');
path.parse()
const Event = require('events').EventEmitter;
let ev = new Event();
// 绑定事件
ev.on('msg', function(a, b,c) {
    console.log(a, b, c); // 12 , 3, 8
})
// 派发事件
ev.emit('msg', 12,3,8);

自己实现一个Events:

class EventEmitter {
    constructor() {
        this._events = {};
    }
    on(eventName, callBack) {
        if (this._events[eventName]) {
            this._events[eventName].push(callBack);
        } else {
            this._events[eventName] = [callBack];
        }

    }
    emit(eventName) {
        this._events[eventName].forEach(fn => {
            fn();
        })
    },
    off(eventName, callBack) {
        this._events[eventName] = this._events[eventName].filter(fn => fn !== callBack)
    }
}

请求url模块

const url = require('url');
url.parse('url', true); // 会解析出url和参数,包含query-string的功能。
  1. TCP 稳定 Net
  2. UDP 快 UDP/Datagram

DNS: 域名解析成ip

const dns = require('dns');
dns.resolve('baidu.com', (err, res) => {
})

基于net的http服务

const http = require('http');
const server = http.createServer((request, response) => {
    // request 为请求数据
    // response 为响应数据
    // 设置返回值类型
    res.writeHead(200, {'Content-type' : 'text/html'});
    response.write = 'server start';
    return response.end(); // 结束
});
server.listen(3000); // 服务监听的端口号