• nodejs学习笔记之包、模块实现


        简单了解了node的安装和一些基本的常识之后,今天学习了node中很重要的包和模块的一些知识点。
     
        首先学习一下包的规范,它由包结构和包描述两部分组成。包结构用于组织包的各种文件,包描述用于描述包的信息,供外部读取分析。
        
        完全符合CommonJS规范的包目录包含一下结构:
        
        package.json: 包的描述文件
        bin: 用于存放可执行的二进制文件的目录 
        lib: 用于存放javascript的目录 
        doc: 用于存放文档的目录 
        test: 用于存放单元测试用例的代码
        node_modules: 第三方模块
        README.md: 关于描述
    

      

        下面以知名框架express项目的package.json文件,讲解一下个参数的含义:
      
    {
      "name": "express", //包名由小写字母和数字组成,包含._-,但不允许空格,包名须是唯一的
      "description": "Sinatra inspired web development framework", //包介绍
      "version": "4.4.4", //版本号,用于版本控制,一般是major.minor.revision格式
      "author": { //包作者
        "name": "TJ Holowaychuk",
        "email": "tj@vision-media.ca"
      },
      "contributors": [ //贡献者列表,每个维护者由name、email和web组成
        {
          "name": "Aaron Heckmann",
          "email": "aaron.heckmann+github@gmail.com"
        },
        {
          "name": "Ciaran Jessup",
          "email": "ciaranj@gmail.com"
        },
        {
          "name": "Douglas Christopher Wilson",
          "email": "doug@somethingdoug.com"
        },
        {
          "name": "Guillermo Rauch",
          "email": "rauchg@gmail.com"
        },
        {
          "name": "Jonathan Ong",
          "email": "me@jongleberry.com"
        },
        {
          "name": "Roman Shtylman"
        }
      ],
      "keywords": [ //关键词数组,有利于用户快速查找到
        "express",
        "framework",
        "sinatra",
        "web",
        "rest",
        "restful",
        "router",
        "app",
        "api"
      ],
      "repository": { //托管源代码的位置
        "type": "git",
        "url": "git://github.com/visionmedia/express"
      },
      "license": "MIT", //许可证列表
      "dependencies": { //当前包所依赖的包列表
        "accepts": "~1.0.5",
        "buffer-crc32": "0.2.3",
        "debug": "1.0.2",
        "escape-html": "1.0.1",
        "methods": "1.0.1",
        "parseurl": "1.0.1",
        "proxy-addr": "1.0.1",
        "range-parser": "1.0.0",
        "send": "0.4.3",
        "serve-static": "1.2.3",
        "type-is": "1.2.1",
        "vary": "0.1.0",
        "cookie": "0.1.2",
        "fresh": "0.2.2",
        "cookie-signature": "1.0.3",
        "merge-descriptors": "0.0.2",
        "utils-merge": "1.0.0",
        "qs": "0.6.6",
        "path-to-regexp": "0.1.2"
      },
      "devDependencies": { //一些模块只有在开发的时候需要依赖,用于提示后续开发者
        "after": "0.8.1",
        "istanbul": "0.2.10",
        "mocha": "~1.20.1",
        "should": "~4.0.4",
        "supertest": "~0.13.0",
        "connect-redis": "~2.0.0",
        "ejs": "~1.0.0",
        "jade": "~1.3.1",
        "marked": "0.3.2",
        "multiparty": "~3.2.4",
        "hjs": "~0.0.6",
        "body-parser": "~1.4.3",
        "cookie-parser": "~1.3.1",
        "express-session": "~1.5.0",
        "method-override": "2.0.2",
        "morgan": "1.1.1",
        "vhost": "2.0.0"
      },
      "engines": { //支持的javascript引擎列表
        "node": ">= 0.10.0"
      },
      "scripts": { //脚本说明对象
        "prepublish": "npm prune",
        "test": "mocha --require test/support/env --reporter dot --check-leaks test/ test/acceptance/",
        "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --require test/support/env --reporter dot --check-leaks test/ test/acceptance/",
        "test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --require test/support/env --reporter spec --check-leaks test/ test/acceptance/"
      },
      "bugs": { //反馈bug的地址
        "url": "https://github.com/visionmedia/express/issues"
      },
      "homepage": "https://github.com/visionmedia/express" //主页地址
    }
    

      

        其次学习一下模块的实现,尽管规范中exports、require、module听起来很简单,我们还是需要了解一下这个过程中究竟经历了什么。
     
        node中引入模块需要经历三个步骤:路径分析、文件定位、编译执行。
        
        我们知道在node中模块主要分为两大部分:核心模块由node本身提供,文件模块由用户编写。它们的执行速度明显核心模块优于文件模块,因为核心模块在node编译的过程中,编译进了二进制执行文件,省略掉了文件定位和编译执行,并且在路径分析中优先判断。文件模块需要完整的路径分析、文件定位和编译执行。需要注意的是node中也有缓存机制,相同的模块在第二次加载的时候,优先从缓存加载,并且核心模块的缓存检查优于文件模块。
     
        第一个步骤:路径分析
        require接收一个表示符作为参数,标识符在node中分为以下几类:
    • 核心模块:如http、fs
    • .或..开始的相对路径文件模块
    • 以/开始的绝对路径文件模块
    • 分路径形式的文件模块
        前三类都很明确根据路径查找,不需要做过多的讲解。文件模块的路径生成规则是:首先查找当前目录下的node_modules目录;其次查找父目录下的node_modules目录;再次查找父目录的父目录下的node_modules;最后不断向上递归查找,直到根目录的node_modules目录。总而言之一句话:一直向上找,直到找到根目录,如果找不到会进入文件文件定位阶段。
     
        第二个步骤:文件定位
        我们知道在我们写require的时可以不叫扩展名,这个时候就需要一个规则,来判断到底使用的是什么后缀的文件,这里就会用到文件定位。首先会补全扩展名查找,补全的顺序是:.js、.node、.json。如果补全之后还没有找到的话,会把这个表示符作为一个目录查找,找到这个目录后会,查找当前目录下是否有package.json,提取main的属性值进行定位,如果没有main的话,会查找index,然后一次查找index.js、index.json、index.node,如果还是找不到的话,就会抛出查找失败的异常。
     
        第三个步骤:编译执行
        编译和执行是引入模块的最后一个阶段。定位到文件后,会新建一个模块对象,然后根据路径载入并编译。对于不同的扩展名,载入方式也不同。
    • .js文件,通过fs模块同步读取文件后编译执行
    • .node文件,这是C/C++编写的扩展文件,通过dlopen()方法加载最后编译生成文件文件
    • .json文件,通过fs模块同步读取文件后,用JSON.parse()解析返回结果
    • 其他文件,它们都被当作.js文件载入
        以上是学习过程中整理的笔记,方便以后学习。
     
     
     
        参考文献:
        深入浅出nodejs -- 朴灵
  • 相关阅读:
    调用微信上传图片的接口
    jqgrid取消列排序
    jqGrid动态添加列
    jqgrid多次调用合并表头出现重叠的处理
    echarts3.0版本断点连线的处理
    JAVA数据转换常用方法
    Java面试常见各种概念区别比较
    Python从零开始(1)新手常问
    记录一下11月份的面试
    Centos7 下安装 mysql8
  • 原文地址:https://www.cnblogs.com/xiaoheimiaoer/p/3803237.html
Copyright © 2020-2023  润新知