nodeJs学习笔记(二)

171 阅读4分钟
模块化
  • 模块导入导出

    新建main.js文件,写入代码

    const age = 18
    const addFn = (x,y) => {
        return x+y
    }
    
    module.exports = {
        age,
        addFn
    }
    

    index.js中进行导入:

    let obj = require('./main.js')
    
    console.log(obj)
    
  • module属性及其常见信息获取

    module的属性上记录了该模块导出的内容、引用信息等

     Module {
      id: 'C:\\Users\\Thomas东\\Desktop\\blog\\webpack学习\\code\\node\\commonJs\\main.js',
      path: 'C:\\Users\\Thomas东\\Desktop\\blog\\webpack学习\\code\\node\\commonJs',       
      exports: { age: 18, addFn: [Function: addFn] },
      parent: Module {
        id: '.',
        path: 'C:\\Users\\Thomas东\\Desktop\\blog\\webpack学习\\code\\node\\commonJs',
        exports: {},
        parent: null,
        filename: 'C:\\Users\\Thomas东\\Desktop\\blog\\webpack学习\\code\\node\\commonJs\\index.js',
        loaded: false,
        children: [ [Circular *1] ],
        paths: [
          'C:\\Users\\Thomas东\\Desktop\\blog\\webpack学习\\code\\node\\commonJs\\node_modules',
          'C:\\Users\\Thomas东\\Desktop\\blog\\webpack学习\\code\\node\\node_modules',
          'C:\\Users\\Thomas东\\Desktop\\blog\\webpack学习\\code\\node_modules',
          'C:\\Users\\Thomas东\\Desktop\\blog\\webpack学习\\node_modules',
          'C:\\Users\\Thomas东\\Desktop\\blog\\node_modules',
          'C:\\Users\\Thomas东\\Desktop\\node_modules',
          'C:\\Users\\Thomas东\\node_modules',
          'C:\\Users\\node_modules',
          'C:\\node_modules'
        ]
      },
      filename: 'C:\\Users\\Thomas东\\Desktop\\blog\\webpack学习\\code\\node\\commonJs\\main.js',
      loaded: false,
      children: [],
      paths: [
        'C:\\Users\\Thomas东\\Desktop\\blog\\webpack学习\\code\\node\\commonJs\\node_modules',
        'C:\\Users\\Thomas东\\Desktop\\blog\\webpack学习\\code\\node\\node_modules',
        'C:\\Users\\Thomas东\\Desktop\\blog\\webpack学习\\code\\node_modules',
        'C:\\Users\\Thomas东\\Desktop\\blog\\webpack学习\\node_modules',
        'C:\\Users\\Thomas东\\Desktop\\blog\\node_modules',
        'C:\\Users\\Thomas东\\Desktop\\node_modules',
        'C:\\Users\\Thomas东\\node_modules',
        'C:\\Users\\node_modules',
        'C:\\node_modules'
      ]
    }
    
  • exports导出数据

    可以直接给exports对象添加属性来导出数据

    exports.name = 'nick'
    
  • 模拟require的实现

    模拟require主要有两个步骤,首先解析所传入的路径,随后根据路径找到文件内容执行即可。在执行之前,首先放到缓存对象中,查找时先查找缓存对象,即缓存优先。

    const { dir } = require('console')
    const fs = require('fs')
    const path = require('path')
    const vm = require('vm')
    
    function Module (id) {
      this.id = id
      this.exports = {}
      console.log(1111)
    }
    
    Module._resolveFilename = function (filename) {
      // 利用 Path 将 filename 转为绝对路径
      let absPath = path.resolve(__dirname, filename)
      
      // 判断当前路径对应的内容是否存在()
      if (fs.existsSync(absPath)) {
        // 如果条件成立则说明 absPath 对应的内容是存在的
        return absPath
      } else {
        // 文件定位
        let suffix = Object.keys(Module._extensions)
    
        for(var i=0; i<suffix.length; i++) {
          let newPath = absPath + suffix[i]
          if (fs.existsSync(newPath)) {
            return newPath
          }
        }
      }
      throw new Error(`${filename} is not exists`)
    }
    
    Module._extensions = {
      '.js'(module) {
        // 读取
        let content = fs.readFileSync(module.id, 'utf-8')
    
        // 包装
        content = Module.wrapper[0] + content + Module.wrapper[1] 
        
        // VM 
        let compileFn = vm.runInThisContext(content)
    
        // 准备参数的值
        let exports = module.exports
        let dirname = path.dirname(module.id)
        let filename = module.id
    
        // 调用
        compileFn.call(exports, exports, myRequire, module, filename, dirname)
      },
      '.json'(module) {
        let content = JSON.parse(fs.readFileSync(module.id, 'utf-8'))
    
        module.exports = content
      }
    }
    
    Module.wrapper = [
      "(function (exports, require, module, __filename, __dirname) {",
      "})"
    ]
    
    Module._cache = {}
    
    Module.prototype.load = function () {
      let extname = path.extname(this.id)
      
      Module._extensions[extname](this)
    }
    
    function myRequire (filename) {
      // 1 绝对路径
      let mPath = Module._resolveFilename(filename)
      
      // 2 缓存优先
      let cacheModule = Module._cache[mPath]
      if (cacheModule) return cacheModule.exports
    
      // 3 创建空对象加载目标模块
      let module = new Module(mPath)
    
      // 4 缓存已加载过的模块
      Module._cache[mPath] = module
    
      // 5 执行加载(编译执行)
      module.load()
    
      // 6 返回数据
      return module.exports
    }
    
事件

nodeJs中事件都是以发布订阅模式,使用on订阅事件,使用emit来发布。

const EventEmitter = require('events')

const ev = new EventEmitter()

ev.on('事件1',() => {
    console.log('事件1执行')
})

ev.emit('事件1')
通信
  • 网络层次模型

    为了方便网络维护管理实施,一共推出了两种网络层次模型:OSI七层模型和TCP/IP四层模型

    OSI七层模型:

    • 应用层:用户与网络的接口,有这个各种面向具体应用的协议,比如HTTP、FTP、SSH等
    • 表示层:数据加密、转换、压缩
    • 会话层:控制网络连接建立与终止
    • 传输层:控制数据传输可靠性,相当于TCP/IP里的传输层
    • 网络层:确定目标网络,相当于TCP/IP里的网际层
    • 数据链路层:确定目标主机
    • 物理层:各种物理设备和标准

    TCP/IP就是在此基础上将引用层、表示层、会话层合并为引用层,最下面的数据链路层和物理层合并为连接层。

  • TCP协议

    TCP属于传输层协议,是面向连接的,用于处理实时通信。

    常见的控制字段有:SYN=1表示请求建立连接、FIN=1表示请求断开连接、ACK=1表示数据信息确认

    TCP三次握手与四次挥手:

    首先三次握手建立连接,客户端向服务端发送SYN=1表示请求链接,服务端发送ACK=1表示信息确认,这里只是建立了一条由客户端向服务端发送信息的通道,还需要建立服务端向客户端的通道。服务端向客户端发送SYN=1表示请求链接,客户端向服务端发送ACK=1表示信息确认,这里一共有这四次握手,只不过第二次和第三次可以合并在一起,即三次握手。

    四次挥手和三次握手的过程类似,即客户端向服务端发送FIN=1表示断开连接,服务端发送ACK=1表示信息确认,服务端向客户端发送FIN=1表示断开连接,客户端发送ACK=1表示信息确认。这里四次挥手为何第二次第三次不合并发送呢,因为当服务端收到客户端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当服务端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉客户端,"你发的FIN报文我收到了"。只有等到我服务端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四次挥手。