zoukankan      html  css  js  c++  java
  • Node.js v10.1.0 Documentation

    Modules

    Stable

    在 Node.js 模块系统中,每个文件都会被当做一个独立的模块。假设有一个名为 foo.js :

    const circle = require('./circle.js');
    console.log(`The area of a circle of radius 4 is ${circle.area(4)}`);
    

    第一行中,foo.js加载了同文件夹下的模块circle.js.
    ·circle.js`中的内容:

    const { PI } = Math;
    
    exports.area = (r) => PI * r ** 2;
    
    exports.circumference = (r) => 2 * PI * r;
    

    模块circle.js 暴露了arear()circumfence() 方法。方法和对象通过对这个特殊的exports对象赋额外的属性值添加到了模块的根中。
    模块的本地变量将是私有的,因为模块被Node.js封装在一个函数中。在本例中,变量PIcircle.js是私有的。
    module.exports属性可以赋值一个新值(例如函数或对象)
    下面,bar.js使用的是square模块,它导出一个Square类。

    const Square = require('./square.js');
    const mySquare = new Square(2);
    console.log(`The area of mySquare is ${mySquare.area()}`);
    

    square模块是在square.js中定义的

    // assigning to exports will not modify module, must use module.exports
    module.exports = class Square {
      constructor(width) {
        this.width = width;
      }
    
      area() {
        return this.width ** 2;
      }
    };
    

    模块系统是在require('module')模块中实现的。

    访问 main module

    node.js直接运行的文件,require.main会被设置为这个文件的module. 由此,可以通过 require.main == module 判断当前文件是否被node.js直接运行 (via node *.js)。
    因为module提供了一个filename属性(通常情况下等于__filename)。当前应用的入口可以通过require.main.filename获取到。

    require 方法的实现

    当调用 require() 方法时, 使用 require.resolve() 方法获取到准确的文件名称,逻辑如下:

    require(X) from module at path Y
    1. If X is a core module,
       a. return the core module
       b. STOP
    2. If X begins with '/'
       a. set Y to be the filesystem root
    3. If X begins with './' or '/' or '../'
       a. LOAD_AS_FILE(Y + X)
       b. LOAD_AS_DIRECTORY(Y + X)
    4. LOAD_NODE_MODULES(X, dirname(Y))
    5. THROW "not found"
    
    LOAD_AS_FILE(X)
    1. If X is a file, load X as JavaScript text.  STOP
    2. If X.js is a file, load X.js as JavaScript text.  STOP
    3. If X.json is a file, parse X.json to a JavaScript Object.  STOP
    4. If X.node is a file, load X.node as binary addon.  STOP
    
    LOAD_INDEX(X)
    1. If X/index.js is a file, load X/index.js as JavaScript text.  STOP
    2. If X/index.json is a file, parse X/index.json to a JavaScript object. STOP
    3. If X/index.node is a file, load X/index.node as binary addon.  STOP
    
    LOAD_AS_DIRECTORY(X)
    1. If X/package.json is a file,
       a. Parse X/package.json, and look for "main" field.
       b. let M = X + (json main field)
       c. LOAD_AS_FILE(M)
       d. LOAD_INDEX(M)
    2. LOAD_INDEX(X)
    
    LOAD_NODE_MODULES(X, START)
    1. let DIRS=NODE_MODULES_PATHS(START)
    2. for each DIR in DIRS:
       a. LOAD_AS_FILE(DIR/X)
       b. LOAD_AS_DIRECTORY(DIR/X)
    
    NODE_MODULES_PATHS(START)
    1. let PARTS = path split(START)
    2. let I = count of PARTS - 1
    3. let DIRS = []
    4. while I >= 0,
       a. if PARTS[I] = "node_modules" CONTINUE
       b. DIR = path join(PARTS[0 .. I] + "node_modules")
       c. DIRS = DIRS + DIR
       d. let I = I - 1
    5. return DIRS
    

    Caching

    modules 当第一次被加载时放到cache中。也就是说每次调用 require('foo') 时,如果解析到同一个文件,将会得到同一返回对象。
    如果想要让一个module多次执行代码,export 一个 function, 然后调用那个 function

    Module Caching 警告

    module基于他们被解析的文件名加载到cache中。由于module可能因为调用module的路径不同而被resolve不同的文件名,所以并不保证每次调用同一个 require(module) 都会返回同一个对象。
    对于大小写敏感的文件系统或者操作系统,即使module被解析为同一个文件,但是因为大小写的原因,module还是会多次加载。

    Core Modules

    Node.js 有一些module被编译为二进制文件,这些module在 Node.js 源文件中定义,位于lib/目录下面。
    Core Module 一直被预加载在cache中。require('http') 将会调用内置的 HTTP module,即使当前目录下面有个名为 http 的文件

    Cycles

    a.js:

    console.log('a starting');
    exports.done = false;
    const b = require('./b.js');
    console.log('in a, b.done = %j', b.done);
    exports.done = true;
    console.log('a done');
    

    b.js:

    console.log('b starting');
    exports.done = false;
    const a = require('./a.js');
    console.log('in b, a.done = %j', a.done);
    exports.done = true;
    console.log('b done');
    

    main.js:

    console.log('main starting');
    const a = require('./a.js');
    const b = require('./b.js');
    console.log('in main, a.done = %j, b.done = %j', a.done, b.done);
    

    output:

    $ node main.js
    main starting
    a starting
    b starting
    in b, a.done = false
    b done
    in a, b.done = true
    a done
    in main, a.done = true, b.done = true
    

    为了防止无穷循环,一个 a.js unfinished copy 会返回给 b.js

    File Modules

    如果没有找到指定名称的问价,Node.js 会尝试添加文件后缀名 .js,.json,.node
    都没有找到会返回 MODULE_NOT_FOUND

    Folders as Modules

    推荐把 programs 和 libraries 组织进一个目录下, 并提供一个统一的入口。有三种方式可以把文件夹的名字作为 require() 方法的参数传送。

    • 在文件夹根目录下创建一个 package.json 的文件,并指定 main mudule。
    { 
       "name" : "some-library",
       "main" : "./lib/some-library.js"
    }
    
    • 创建一个index.js的文件作为入口
    • 创建一个index.node的文件作为入口

    Loading from node_modules Folders

    如果给 require() 传递的 module 名称不是一个 core module, 并且没有以 '/','../','./'作为开始, 那么Node.js 会尝试从 node_modules 目录下面查找所需要的module。
    举例来说:有一个位于 ''/home/ry/projects/foo.js'' 调用 require('bar.js'), node.js 回按照下面的方式顺序查找 bar.js

    • /home/ry/projects/node_modules/bar.js
    • /home/ry/node_modules/bar.js
    • /home/node_modules/bar.js
    • /node_modules/bar.js
      此外,可以使用已知路径的 module 作为参考,去查找相对于这个 module 的 其他 module;

    Loading from the global folders

    如果在 node_modules 里仍然没有找到指定的module,Node.js 会搜索系统环境变量 NODE_PATH 指定的目录。当然,前提是设置了这个环境变量。
    墙裂推荐把相关 module 放在 node_modules目录下面,这样加载会更快更稳定。

    The module wrapper

    当一个module里面的代码被执行之前,Node.js 会先把module里面的代码封装起来:

    (function(exports, require, module, __filename, __dirname) {
    // Module code actually lives in here
    });
    

    这样做的优点是:

    • 会把变量限定在这个module里面,而不是global对象下面。
    • 提供一些貌似global的对象。(export,'require,'module','__filename,'__dirname`)

    The module scope

    __dirname (type:string)

    Example: 运行node example.js from /Users/mjr

    console.log(__dirname);
    // Prints: /Users/mjr
    console.log(path.dirname(__filename));
    // Prints: /Users/mjr
    

    __filename(type:string)

    Example: 运行node example.js from /Users/mjr

    console.log(__filename);
    // Prints: /Users/mjr/example.js
    console.log(__dirname);
    // Prints: /Users/mjr
    

    给定两个文件a.js 和 b.js , a.js 依赖 b.js, 将会有如下的结构

    • /Users/mjr/app/a.js
    • /Users/mjr/app/node_modules/b/b.js

    exports

    等同于 module.exoports

    module (type:object)

    当前module

    require() (type:function)

    用于调用依赖module

    require.cache(type:object)

    所有通过require方法调用过的依赖都存储于这个对象当中。如果删除了对象中的某个Key,下一次调用 require() 方法时会重新加载这个module。但是这个方法不适用 native addons.

    require.extensions(弃用)

    require.main(type:object)

    代表程序启动时的入口module.

    require.resolve(request[这个是参数])

    使用 require的机制去查找某个 module 的路径,但是只返回解析到的 filename, 而且不加载这个module.

    require.resolve.paths(request[这个也是参数])

    返回查找某个module遍历的路径信息(type:string[] | )
    如果是core module, 返回 null

    The module Object

    module.children:当前module所有的依赖项
    module.exports:可以用来赋值某个类的实例(exports 不可以)
    a.js:

    const EventEmitter = require('events');
    module.exports = new EventEmitter();
    // Do some work, and after some time emit
    // the 'ready' event from the module itself.
    setTimeout(() => {
     module.exports.emit('ready');
    }, 1000);
    

    b.js:

    const a = require('./a');
    a.on('ready', () => {
     console.log('module "a" is ready');
    });
    

    赋值操作需要马上完成,不可以在会掉中完成。下面的代码是不会有效的:
    x.js:

    setTimeout(() => {
     module.exports = { a: 'hello' };
    }, 0);
    

    y.js:

    const x = require('./x');
    console.log(x.a);
    

    其他属性
    module.filename:<string> 全文件名
    module.id:<string> module 标识 通常是全文件名
    module.loaded:<boolean> module是否已加载
    module.parent:<module> 第一个调用这个module 的 module
    module.paths:<string[]> 搜索路径
    module.require(id):module外调用require的方法

    源链接

  • 相关阅读:
    18个Java开源CMS系统一览
    冒泡排序
    数据挖掘十大经典算法
    开源Java CMS建站程序推荐
    Oracle
    Oracle Procedure returning Ref Cursor in Entity Framework 4
    Field_II
    SharePoint Video Library
    ORACLE 导入dmp文件
    System.Diagnostics.Process.Start()。它的作用是调用外部的命令
  • 原文地址:https://www.cnblogs.com/ArvinZhao/p/9067051.html
Copyright © 2011-2022 走看看