nodejs start2

396 阅读2分钟

nodejs 模块分类

  1. 核心模块|内置模块: fs buffer require("fs")
  2. 第三方模块 ejs commander 需要安装 require('ejs')
  3. 文件模块 必须要有./或绝对路径 自己写的 require(./../../xx)

如何调试nodejs代码

  • 用vscode自带的功能
  • node --inspect-brk 3.module.js 浏览器chrome://inspect 辅助调试

fs的模块 总有同步和异步

  • fs.accessSync(//绝对路径) //判断文件是否存在 读写文件的操作一律使用绝对路径
  • ______dirname 当前文件的工作目录
    __filename 当前工作目录下的文件名
  • path.resolve('a','a.js') // /users/xx/xxx/xxxx/a/a.js 项目目录拼接a/a.js 会解析出绝对路径
    path.join('a','a.js') // a/a.js 直接拼接 如果参数有'/'不要用resolve
    path.dirname() //取父路径
    path.extname('a.js') // .js 返回文件后缀

手动实现一个require函数

  1. 加载模块 Module._load(文件名)
  2. 看一下当前这个模块有没有缓存过 有直接使用 无go on
  3. Module._resolveFilename 解析参数 把相对路径转化为一个绝对路径
  4. 通过路径创建一个模块 1) 文件名 ; 2) exports对象
  5. 将模块放到缓存中
  6. 加载模块 根据后缀名调用对应的方法 Module._extensions
  7. 读取文件
  8. 添加闭包
  9. 运行在沙箱环境中
const path = require('path')
const fs = require('fs')
const vm = require('vm')
function req(filepath) {
  return Module.load(filepath)
}
Module.load = function (filepath) {
  // 获得文件绝对路径
  let finalPath = Module.resolveName(filepath)
  if (finalPath) {
  // 有缓存则返回缓存的exports
  if (Module._cache[finalPath]) return Module._cache[finalPath].exports
    // 新建一个模块
    let module = new Module(finalPath)
    Module._cache[finalPath] = module // 把模块放入缓存中
   return module.load()
  }
}
// 模块缓存
Module._cache = {}
function Module(id) {
  this.id = id
  this.exports = {}
}
Module.prototype.load = function () {
  const extname = path.extname(this.id)
  // 根据后缀名调用对应的文件加载方法
  Module.extensions[extname](this) // 传入当前模块
  return this.exports // 返回exports对象
}
Module.wrapper = ["(function(exports,module,require,__dirname,__filename){","\n})"]
Module.extensions = {
  '.js'(module) {   
    let content = fs.readFileSync(module.id, 'utf-8') // 读取文件内容
    console.log('content', content)
    let scriptStr = Module.wrapper[0] + content + Module.wrapper[1] //放在自执行函数内
    let fn = vm.runInThisContext(scriptStr) // 通过node虚拟机 在沙箱中 将函数字符串转化为真正可执行的函数
    // console.log(fnStr.toString())
     fn.call(module.exports,module.exports,module,req) // 传入实例,给实例this上的属性赋值 
   },
  '.json'(module) {
  const fileContent = fs.readFileSync(module.id,'utf-8')
    console.log('content', fileContent)
    module.exports = JSON.parse(fileContent) // 直接导出
  }
}
Module.resolveName = function (pathname) {
  const absPath = path.resolve(__dirname, pathname)
  // console.log(absPath)
  let finalPath = absPath
  if (!path.extname(absPath)) {
    // 当没有设置后缀的时候,从Module.extensions里去取来拼接
   let has = Object.keys(Module.extensions).find(ele => {
      finalPath = absPath + ele
      // console.log('final', finalPath)
      try {
        fs.accessSync(finalPath)
        return true
      } catch (error) {
        console.error(`不是${ele}的文件额`)
      }
   })
    // 拼接完以后,没有找到
    if (!has) {
      finalPath = ''
      throw new Error('文件不存在')
    } 
  } else {
    try {
      fs.accessSync(finalPath)
    } catch (error) {
      final = ''
      console.error(`文件不存在`)
    }
  }
  return finalPath
}
let result = req('./useAtest')
console.log(result)