zoukankan      html  css  js  c++  java
  • nodejs中 require 方法的加载规则

    require参数类型

    • http、fs、path等,原生模块
    • ./mod或../mod,相对路径的文件模块
    • /pathtomodule/mod,绝对路径的文件模块
    • mod,非原生模块的文件模块

    在进入路径查找之前有必要描述一下module path这个Node.js中的概念。对于每一个被加载的文件模块,创建这个模块对象的时候,这个模块便会有一个paths属性,其值根据当前文件的路径计算得到。Node.js在编译js文件的过程中实际完成的步骤有对js文件内容进行头尾包装。以app.js为例,我们将其放在任意一个文件夹中,包装之后的app.js将会变成以下形式:

    (function (exports, require, module, __filename, __dirname) {
        console.log(module.paths);
    });

    在app.js中输入如下内容:

    console.log(module.paths);

     执行node module app.js命令,将得到以下的输出结果:

    [ '/home/jackson/research/node_modules', 
    '/home/jackson/node_modules', 
    '/home/node_modules', 
    '/node_modules' ]

    Windows下:

    [ 'c:\nodejs\node_modules', 
    'c:\node_modules' ]

     可以看出module path的生成规则为:从当前文件目录开始查找node_modules目录;然后依次进入父目录,查找父目录下的node_modules目录;依次迭代,直到根目录下的node_modules目录。

    除此之外还有一个全局module path,是当前node执行文件的相对目录(../../lib/node)。如果在环境变量中设置了HOME目录和NODE_PATH目录的话,整个路径还包含NODE_PATH和HOME目录下的.node_libraries与.node_modules。其最终值大致如下:

    [NODE_PATH,HOME/.node_modules,HOME/.node_libraries,execPath/../../lib/node]

    require方法中的文件查找策略(指内置模块和第三方模块):

    1、从module path数组中取出第一个目录作为查找基准。 

    2、直接从目录中查找该文件,如果存在,则结束查找。如果不存在,则进行下一条查找。 

    3、尝试添加.js、.json、.node后缀后查找,如果存在文件,则结束查找。如果不存在,则进行下一条。

    4、尝试将require的参数作为一个包来进行查找,读取目录下的package.json文件,取得main参数指定的文件。 

    5、尝试查找该文件,如果存在,则结束查找。如果不存在,则进行第3条查找。 

    6、如果继续失败,则取出module path数组中的下一个目录作为基准查找,循环第1至5个步骤。 

    7、如果继续失败,循环第1至6个步骤,直到module path中的最后一个值。 

    8、如果仍然失败,则抛出异常。

    文件查找流程:

    由于 Node.js 中存在 4 类模块(原生模块和3种文件模块),尽管 require 方法极其简单,但是内部的加载却是十分复杂的,其加载优先级也各自不同。如下图所示:

    一、优先从文件模块缓存中加载

    尽管原生模块与文件模块的优先级不同,但是都会优先从文件模块的缓存中加载已经存在的模块。

    二、原生模块

    原生模块的优先级仅次于文件模块缓存的优先级。require 方法在解析文件名之后,优先检查模块是否在原生模块列表中。

    在实际开发过程中,如果你的文件和核心库文件同名,加载过程中是会直接忽略你的项目文件。

    例如在server下有config.json,require("config")。

    require具体的加载过程是:

    (1)核心库中如果有config.js 会直接加载 忽略你的文件。

    (2)如果没有会检查你的项目中是否有这个.js文件。

    (3)如果没有才会去查询 .json 文件。

    所以在开发过程中最好使用其相对路径指明具体文件。

    当第三方的模块和内置模块同名时,内置模块将覆盖第三方同名模块。因此命名时需要注意不要和内置模块同名。

    原生模块也有一个缓存区,同样也是优先从缓存区加载。如果缓存区没有被加载过,则调用原生模块的加载方式进行加载和执行。

    原生模块的本质也是文件,原生模块文件已经被编译到了二进制文件中了,我们只需要按照名字来加载就可以了。如:

    1、require(‘fs’)

    2、require(‘http’)

     三、路径形式的模块

    我们说的路径形式的模块,其实就是加载自己写的JS文件,有四种方式可以加载

    当文件模块缓存中不存在,而且不是原生模块的时候,Node.js 会解析 require 方法传入的参数,并从文件系统中加载实际的文件 。

    var fooExports = require('./index')	//相对路径,常用
    var fooExports = require('../index')	//相对路径,常用
    var fooExports = require('/index')	//根目录,不常用
    var fooExports = require('D:/demo/index')	//根目录,不常用

    注意,这里忽略了扩展名“.js”,以下是对等的:

    var myMod = require('./my_mod')
    var myMod = require('./my_mod.js')

    如果当前目录有my_mod.js和my_mod.json,则会优先加载 my_mod.js。

    可以直接require一个目录,假设有一个目录名为folder,如:

    var myMod = require('./folder')

    此时,Node将搜索整个folder目录,Node会假设folder为一个包并试图找到包定义文件package.json。如果folder 目录里没有包含package.json文件,Node会假设默认主文件为index.js,即会加载index.js。如果index.js也不存在, 那么加载将失败。 

    假如目录结构如下:

    package.json定义如下:

    {
        "name": "pack",
        "main": "modA.js"
    }

    此时 require('./folder') 将返回模块modA.js。如果package.json不存在,那么将返回模块index.js。如果index.js也不存在,那么将发生载入异常。 

    如果foder同级目录还有folder.js和folder.json,同时folder目录下还有index.js,则require('./folder') 将返回folder.js中的内容,否则返回folder.json中的内容,否则会返回folder目录下index.js中的内容,最后才会返回modA.js中的内容。

     四、第三方模块

    凡是用到第三方模块,都必须通过 npm 来下载;

    使用的时候就可以通过 require(‘包名’) 的方式来进行加载才可以使用;

    不可能有任何一个第三方包和核心模块的名字是一样的。

    既不是核心模块、也不是路径形式的模块,就是第三方模块。

    如果模块名不是路径,也不是内置模块,Node将试图去当前目录的node_modules文件夹里搜索。如果当前目录的node_modules里没有找到,Node会从父目录的node_modules里搜索,这样递归下去直到根目录。

    总结:

    其实主要就是两种情况:

    1、如果require中是名称,则说明搜索的是内置模块或者第三方模块,此时内置模块的优先级高于第三方模块;

    2、如果require中是路径,则会按照自定义模块的规则查找。

  • 相关阅读:
    c++vector(入门级)
    端口扫描(TCP)
    推荐安全程序员的书单(系统、网络、安全等)
    My latest news(--2016.12.31)
    HTML+JS+DOM【选项卡自动切换】
    20170916考试总结
    [Usaco2014 Mar]Sabotage
    [SHOI2014]概率充电器
    [Usaco2010 Dec]Exercise 奶牛健美操
    [JZOJ4687]奇袭
  • 原文地址:https://www.cnblogs.com/samve/p/10805908.html
Copyright © 2011-2022 走看看