美文网首页
node的模块加载

node的模块加载

作者: 田成力 | 来源:发表于2019-10-09 20:45 被阅读0次

    Node的模块加载

    Node的REPL

    R:读
    E:eval计算
    P:写
    L:loop

    console

    标准流 1

    • console.log()
    • console.info()
      错误流2
    • console.warn()
    • console.error()
      测试时间
      console.time('a')
      console.timeEnd('a')
      //TDD测试驱动开发、BDD行为驱动开发,单元测试
      断言
      console.assert()
      如果表达式表达为真就不输出,为假就报错,用于监控
    function sun(a,b){
    return a+b
    }
    console.assert(sum(1,2)==3,'报错')
    

    console.dir()
    //可以列出对象的的结构
    console.trace();
    //可以跟踪当前代码的调用栈
    //程序执行从上往下执行,栈是先进后出

    global全局对象

    window里也有全局对象,但是不能直接访问,我们在浏览器里访问global是通过window实现的
    1.global的变量是全局变量
    2.所有的全局变量都是global的属性
    console.log(global)
    //chdir:改变目录
    //cwd:当前工作目录

    • process当前进程
      process.cwd()
      process.chdir()
      nextTick 把回调函数放在当前执行栈的底部
      setImmediate把回调函数放在事件队列的尾部

    回顾 简易版的模块加载

    
      const fs = require('fs');
      const path = require('path');
      const vm = require('vm')
    
    
    
      class Module {
        constructor(filepath) {
          this.id = filepath;
          this.exports = {};
        }
        load() {
          //读取文件:
          let fileContent = fs.readFileSync(this.id, 'utf8');
    
          //包装文件
          fileContent = '(function(exports,module,require){' + fileContent + '})';
          let fn = vm.runInThisContext(fileContent);
          fn(this.exports, this, req);
          return this.exports;
        }
      }
      function req(filepath) {
    
        //文件的路径:
        let absolutepath = path.join(__dirname, filepath);
    
        let module = new Module(absolutepath);
    
    
        //加载模块
        return module.load();
    
      }
    
      const a = req('./a.js');
      console.log(a);//hello
    
    

    升级版

    添加对json的处理
    添加缓存

        const fs = require('fs');
        const path = require('path');
        const vm = require('vm')
    
        const ModuleCache = {};
        class Module {
          constructor() {
            this.id = "";
            this.exports = {};
          }
    
    
          processFile() {
            return {
              ".js":(filepath)=> {
                let fileContent = fs.readFileSync(filepath, 'utf8');
                fileContent = `(function(module,exports,require,__filename,__dirname){${fileContent}})`;
                let fn = vm.runInThisContext(fileContent);
                fn(this, this.exports, req, filepath, path.dirname(filepath));
              },
              ".json":(filepath)=> {
                let fileContent = fs.readFileSync(filepath, 'utf8');
                this.exports = JSON.parse(fileContent);
              }
            }
          }
    
    
          load(filepath) {
            filepath = this.getFileAbsoultePath(filepath);
            this.id = filepath;
            //判断是否缓存过了
            if (ModuleCache[this.id]) {
              //加载过了
              return ModuleCache[this.id].exports;
            }
            let extname = path.extname(filepath);
            this.processFile()[extname](filepath);
            //添加缓存
            ModuleCache[this.id] = this;
            return this.exports;
          }
    
          getFileAbsoultePath(filepath) {
            //判断是否有后缀名
            //如果有直接使用
            //如果没有 匹配后缀
            if (filepath.indexOf('/') != 0) {
              //传入的是相对路径
              filepath = path.join(__dirname, filepath);
              console.log("filepath===>",filepath);
              
            }
            let extname = path.extname(filepath);
            if (!extname) {
              let canProcessExtnames = Reflect.ownKeys(this.processFile());
              for (let index = 0; index < canProcessExtnames.length; index++) {
                const currentExtname = canProcessExtnames[index];
                filepath += currentExtname;
                if (fs.existsSync(filepath)) {
                  //找到文件了
                  break;
                } else {
                  filepath = null;
                }
              }
            } else {
              //自带了后缀名
              if (!fs.existsSync(filepath)) {
                throw new Error("not find file");
              }
            }
            if (filepath) {
              return filepath;
            }
            throw new Error('not find file')
    
          }
        }
    
        function req(filepath) {
          let module = new Module();
          return module.load(filepath);
        }
    
        const a = req("./a");
        console.log(a);//hello
    
    

    exports 和 module.exports的关系

    
    console.log(exports===module.exports);//true
    
    // 实际上的形参 和实参 是这样的
    let fn=function(module,exports,require,__filename,__dirname){xxxx}
    
    fn(module,module.exports,require,xx,xx);
    
    //可以看到 exports就是module的属性
    
    //但问题是 为什么不能写成
    //a.js文件
    
    exports 'hello'
    
    //根据关系我们可以模拟出下面的代码
    var obj={arr:[1,2,3]}
    var arr=obj.arr;
    arr=[4,5,6]
    
    // 这时候的arr和obj.arr还相同吗
    // 我们用obj.arr能用到[4,5,6]吗
    
    

    模块的加载顺序

    文件模块

    1. 通过文件的路径找对应的文件 如果文件存在,则加载文件
    2. 如果文件不存在,则找同名文件夹/index.js文件

    第三方模块

    1. 通过名称在自己的目录的node_modules中找对应的文件夹
    2. 找到该文件夹下的package.json文件中的main字段对应的文件加载文件
    3. 如果没有package.json 或是没有main字段,则会默认找文件夹下的index.js或index.json文件并加载
    4. 如果还找不到,则再向上一层查找node_modules文件夹

    内置模块

    1. 通过名称引用 优先引用

    相关文章

      网友评论

          本文标题:node的模块加载

          本文链接:https://www.haomeiwen.com/subject/vwhnpctx.html