node简记(一)

概念:

  • 列表内容

  • node中的每个被加载的文件对应一个模块对象

  • 一个文件/模块被第一次加载后,会在内存中保存对应的缓存对象;对一个模块多次重复引入,会使用该缓存对象,从而避免了重复加载导致创建出多个完全相同的模块对象。
  • 模块的分类

    ·不带路径的模块名带路径的模块名
    文件模块Node.js核心模块,如http应用中自定义文件模块
    目录模块node_modules下的目录模块,如:mysql应用中的自定义目录模块
  • 在自定义目录模块中入口模块默认为index.js,可以在config.json文件中设置main字段为自定义入口模块


全局对象

  • console
    • log/info/error/warn/trace/assert/time/timeEnd
      • time(“myLabel’)——启动一个定时器,唯一的标识myLabel
      • timeEnd(‘myLabel’)——结束一个标识为myLabel的定时器,并结束该定时器,并返回定时器一共运行的持续时间
console.assert(expression,"error msg");  //当expression执行的结果为假的时候,抛出一个错误的信息提示哪里出错了,并结束程序的运行
  • __dirname
    • 输出当前所在的文件夹所在的路径
    • (eg:/Users/mjr)
  • __filename
    • 输出当前文件的绝对路径
    • (eg:/Users/mjr/example.js)
  • process

    • 程序:是存放在磁盘上的一些指令的有序集合
    • 进程:程序运行起来之后,操作系统分配系统资源的基本单位
    • 线程:每一个进程中 至少有一个线程,线程是cpu(根据时间片轮转给线程时间执行)调用的基本单位
    • process.pid //获取当前进程的进程编号
    • process.arch //当前架构
    • process.platform //平台
    • process.argv //获取启动时传入的数组组成的数组
    • process.env //当前主机启动node进程,运行环境变量
    • process.kill(要结束的进程编号) //结束掉指定的进程
    • process.hrtime() //获取一个精确到纳秒的时间
  • timer 定时器 nodejs提供了4种形式的定时器

    • timeout 一次性定时器 (setTimeout/clearTimeout)
    • interval 周期性定时器 (setInterval/clearInterval)
    • immediate 下次事件循环立即执行 (setImmediate/clearImmediate)
    • process.nextTick 本次事件循环结束后之后立即执行

      事件循环机制:
      timers(定时器) -> io callback(回调) -> io polling(轮询去判断有没有io事件产生 ) -> set immediate(立即执行) -> close events(关闭事件)
      这是事件循环的一个tick,每此循环都是一个tick

setTimmediate(()=>{
    console.log(1);
})

setTimeout(()->{
    console.log('2');
},0)

process.nextTick(()=>{
    console.log('3');
})
function test() {
    console.log('4');
}
//返回 4,3,2,1
//先执行同步,后执行异步

模块系统

  • 基本用法
    • 在node.js中 文件/目录都可以是一个模块
    • 导出:module.exports = xxx
    • 引入:require(‘文件的相对路径’)
  • 本质

    • nodejs模块文件的本质——是一个构造方法的执行体

      function(exports,require,module,__dirname,__filename){
          module.exports = {};
          exports = module.exports;
          //开发者要写的代码
          ...
      }
  • 在模块化系统中,一个模块只要被引入了一次,就会一直保留这个实例对象,在其他地方反复调用,都会指向第一次所执行的对象(单例模式)


模块

  • Console模块

    • 提供了一种控制台调试输出机制,类似于Chrome浏览器中console对象的功能
    • 该模块向外导出了两个成员:

      • Console class:可用于向任意Node.js输出流对象执行输出
      • global.console实例:可用于向stdout和stderr中执行输出

        const fs = require("fs");
        const console = require("console");
        let outFile = fs.createWriteStream('./out.log');  //有此文件则删除其中内容,无此文件则新建
        let errFile = fs.createWriteStream('./err.log');
        let loggerConsole = new console.Console(outFile,errFile);
        loggerConsole.log('%d:this is a log',new Date().getTIme());
        loggerConsole.info('%d:this is a info',new Date().getTIme());  //向标准流对象中输出
        loggerConsole.warn('%d:this is a warn',new Date().getTIme());  //向错误流对象中输出
        loggerConsole.error('%d:this is a error',new Date().getTIme());
  • os模块

    • 提供了很多用于获得当前操作系统信息的方法

      const os = require('os');
      os.EOL  //end of line的常量
      os.tmpdir()  //os的临时目录
      os.hostname()  //当前主机名
      os.platform()   //当前平台类型
      os.uptime()   //当前已经运行的时间,单位秒
      os.totalmem()  //os总内存大小,单位为字节
      os.cpus() //返回所有cpu内核信息
      os.networkInterfaces()  //返回所有网络接口信息
  • Readline模块

    • 读取一行数据的模块,遇到\n就停一次,
    • Readline模块中有一个interface对象,可用于从标准输入对象或者其他输入流对象中一行一行的读取数据

      const readline = require('readline');
      let reader = readline.createInterface({
          input:process.stdin,   //从哪读
          output:process.stdout  //在哪写
      });
      reader.question("Input user name:",line=>{
          console.log("Logging in as user %s..",line);
          reader.close();  //使用完必须关闭,否则解释器不会退出
      })
      //从屏幕中读,向文件中写
      const fs = require('fs');
      const os = require('os');
      var outFile = fs.createWriteStream('./1.txt');
      var r1 = readline.createInterface({
          input:process.stdin,
          output:process.stdout,
          prompt:'请输入一个员工姓名 >'
      })
      r1.prompt();   //显示提示信息
      r1.on('line',line=>{
          if(line!=='byebye') {
              outFile.write(line+os.EOL);  //写出到文件中
              r1.prompt();  //显示提示信息
          } else {
              r1.close();
              outFile.close();    
          }
      })
      //把文件(1.txt)中的内容一行一行实现逐行复制到另一个文件(2.txt)中
      var inFile = fs.createReadStream('2.txt');
      var outFile = fs.createWriteStream('1.txt');
      var reader2 = readline.createInterface({
          input:inFile,
          output:process.stdout,
          terminal:false
          //output: outFile,
          //terminal:true 
      });
      var counter = 0;
      reader2.on('line',line=>{
          //手动输出
          counter++;
          console.log(counter+" "+line);
          outFile.write(counter+" "+line+os.EOL);
      })
  • querystring模块

    • 将一个查询字符串解析为对象,将对象序列化为字符串

      const qs = require('querystring');
      var str = 'a=1&b=1&c=1';
      var data = qs.parse(str);
      console.log(data);
      var str2 = data.stringify(data);
      console.log(str2);
  • url模块

    • url模块提供了处理url中不同部分的相关操作。

      const = require('url');
      var url1 = 'http://root:123456@www.baidu.com:8080/sub/index.html?uname=abc&age=11#chapter3';
      var obj1 = url.parse(url1,true);  //解析查询字符串
      console.log(obj1);
      
  • path模块

    • 提供了对文件路径进行操作的相关方法;这些方法只是进行了字符串的相关转换,与文件系统本身没有任何关联

      const path = require(path);
      //解析路径字符串
      console.log(path.parse('c:/user/local/img/1.jpg'));
      //将路径对象格式化为字符串
      var obj = {dir:'c:/user/local/img',base:'1.jpg'};
      console.log(path.format(obj));
      //根据基础路径解析出一个目标路径的绝对路径
      console.log(path.resolve('c:/user/local/index.html','../img/1.jpg'));
      //根据基础路径,获取目标路径与其的相对关系
      console.log(path.relative('c:/user/local/index.html,local/img/1.jpg'));
      
  • DNS模块

    • 提供了域名到IP地址的双向解析功能;包含如下三个主要方法
      const dns = require('dns');
      //将一个域名解析为一个DNS记录解析数组
      dns.resolve('baidu.com',(err,addr)=>{
          console.log(addr);
      })
      //将一个域名解析为一个IP地址
      dns.lookup('baidu.com',(err,addr,family)=>{
          console.log(addr);
      })
      //将一个ip地址反向解析为一组域名
      dns.reverse('61.135.169.121',(err,hostname)=>{
          console.log(hostname);
      })
  • util模块

    • 提供了若干工具方法,供node.js其他模块和应用开发者使用

      const util = require('util');
      //使用带占位符的格式化字符串
      var data = {name:'Cola',price:2.5,isOnsale:false}
      console.log(util.format('NAME:%s PRICE %d ISONSALE:%s',data.name,data.price,data.isOnsale));
      //返回一个对象的字符串形式
      console.log(util.inspect(data));
  • Error模块

    • 在node.js中“错误对象“分为四种类型:

      • 原生js提供的错误类型:EvalError SyntaxError RangeError ReferenceError TypeError URIerror
      • 由操作系统底层限制引起的自动错误,如打开不存在的文件/向关闭的流中写出数据
      • 断言错误
      • 应用程序抛出的用户自定义错误
    • node.js中所有的错误对象都是Error类型的实例

      • Error对象可以使用throw关键字进行抛出
      const fs = require('fs');
      try {
          fs.readFile('不存在的文件',(err,data)=>{
              if(err) {
                  //异步函数抛出错误不能用try..catch捕获,只能以事件回调的方式进行处理
                  throw err;
              }
          })
      } catch(err) {
          console.log(err);
      }
  • HTTP模块

    • 提供web服务的模块
  • express模块

    • 提供web服务的一个针对node的轻量级的框架,是对http的封装。
    • 处理请求方式 : app.get('/',(req,res)=>{});
    • send() 方法返回字符串
  • mysql模块

    • 针对mysql的一个node.js驱动

      let connection = mysql.createConnection({
      host:'localhost',
      user:'root',
      password:'',
      database:'xz'
      })
      //连接数据库后,发送sql语句,回调拿到返回结果
      connection.query('select * from xxx',(err,results,fields)=>{
      if(err) throw err;
      console.log(result);
      })

辅助模块:
supervisor 用在开发阶段,自动重启服务
forever 在node服务崩溃之后,依然能够持续的运行脚本文件的模块


进程 & 线程

进程(process):程序从外存载入内存,分配可执行程序要用到的空间,随时准备cpu执行(车间,单个cpu同时只能执行一个进程)
线程(thread):线程是进程内部可供cpu执行代码的最基本单位(车间的工人)

  • 每个线程需要自己独立的数据内存空间,大小为2MB,所以,一台具有8G内存的计算机,理论上可以同时存在4000个线程
  • 一个进程内也可以同时存在多个线程,这些线程并发执行(宏观上是同时执行,微观上是轮流执行)
  • cpu在并发执行操作系统中的所有线程时,采用的是”时间片轮转法”——每个线程最多只能执行5ns,即使没有执行完所有代码,也必须让出cpu

单线程服务器

  • 经典的”单线程模型”中,服务器端只有一个线程,以此为每个客户端提供服务,程序设计简单,但运行效率低
  • node.js采用基于事件循环的非阻塞式(背后的异步回调函数是底层的libuv处理的,单线程主要指的是执行js代码的线程,而异步IO是nodejs利用libuv去进行异步处理的)单线程模型,在保证了每个请求都可以快速得到响应的同时,实现了远远超过多线程模型的并发数。其特点是:
    • 服务器端只有一个请求服务线程
    • 所有的请求都会在“事件循环队列“中等待
    • 请求服务线程依次为每个请求服务,但不会因为请求而阻塞

多线程服务器

  • 服务器端同时创建了多个服务进程,并发的为多个客户端提供服务
  • 结果复杂,性能好,可以充分利用cpu的优势
  • 缺点:
    • 每个线程内部的操作都是线性执行的,耗时操作会阻塞后续操作
    • 受限于线程总数的限制,无法并发的处理大量的请求
    • 过多过频繁的线程上下文切换,产生了更多的cpu开销
    • 多线程并发往往伴随者互斥和死锁等问题,增加了程序设计复杂度

事件循环

在nodejs启动时,会创建一个类似于while(true)的循环体,每次执行一次循环体,称之为一个tick,每一个tick过程就是查看是否有事件等待处理,如果有,则取出事件以及相关的回调函数去执行;执行完之后,进入到下一个tick(所有异步的处理都不会在本次tick中处理,除了nextTick)

阻塞(block):同步执行,只有前面的操作全部执行完成,才能开始后续的操作

非阻塞(unblock):给定一个耗时操作,当耗时操作执行完毕之后,在以后的事件循环中,执行callback所对应的代码

同步(sync):

异步(async): 当一个任务执行时,可以开启另一个任务

阻塞与同步是同一概念吗?
不是。举个例子:A先做到第一步,此时B等待(阻塞)。等到A执行完成,B接着继续做第二步(阻塞结束),整个过程,称为A和B**同步**执行

Nodejs添加新的事件回调函数有5种方式:

  1. 原生模块预定义的事件和事件监听处理函数
    原生模块指的就是nodejs内置的一些模块
  2. 异步I/O库
  3. 定时器回调
  4. 全局对象process.nextTick
  5. 自定义事件

定时器回调

console.log(1);
setTImeout(()=>{
    console.log(2);
},0)
console.log(3);

setImmediate(()=>{
    console.log(4);
});
process.nextTick(()=>{
    console.log(5);
})
console.log(6);
//返回 1 3 6 5 2 4
//同步代码执行完毕后才会执行异步操作
//在事件循环中 timerimmediate前面,而nextTick在本次EventLoop的尾部执行


自定义事件

  • (events模块)所有对象都能够触发events事件,作为EventEmitter类的实例。实例暴露出eventEmitter.on()方法用来将一个或多个函数绑定到命名事件上
//引入events模块,实现异步自定义事件回调
const eventEmitter = require('events'); 
//创建一个触发器实例
const myEmiiter = new eventEmitter();
//自定义事件绑定
myEmitter.on('customEvent',(a,b)=>{
    console.log(a,b,this);
})
//tips: 这里的addListener()方法就是on方法的别名

//触发自定义事件并传参
myEmitter.emit('customEvent',a,b);

______________________________________________________________

//当需要把相关的事件的处理放在一起来管理时,建议继承eventEmitter来单独的创建一个类 在继承类中处理事件
class DeliveryOrder extends eventEmitter{
    //准备在构造函数中 提前将用到的事件和事件处理函数绑定好
    constructor(){
        super()
        //事件的绑定
        this.on('newDeliveryOrder',()=>{
            console.log('收到了新的消息')
        })
    }

  //定义用来触发事件的方法
  submitOrder(){
    this.emit('newDeliveryOrder')
  }
}
var myDeliveryOrder = new DeliveryOrder();
myDeliveryOrder.submitOrder();

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值