commonjs和nodejs,commonjs和node

  commonjs和nodejs,commonjs和node

  node.js速度课程简介:进入学习

  Node的应用是由模块组成的,其模块体系借鉴了CommonJS模块规范,但并没有完全按照规范实现,而是根据自身需要增加了一些特性,可以看作是CommonJS模块规范的变种。

  

CommonJS概述

   CommonJS是社区提出的JavaScript模块化规范,可以说是JS模块化历程中最重要的里程碑。它构造了一个——JS可以在任何地方运行的美好愿景,但实际上由于其模块是同步加载的,所以只适用于服务器等其他本地环境,不适合浏览器等需要异步加载资源的地方。

  为了让JS可以在任何地方运行,CommonJS制定了一些接口规范,涵盖了模块、二进制、缓冲区、字符集编码、I/O流、进程环境、文件系统、socket、单元测试、web服务器、网关、包管理等。虽然大部分都处于草案阶段,但是已经深深影响了Node的发展。

  下图是节点和浏览器,W3C,CommonJS和ECMAScript的关系,取自《深入浅出NodeJS》。

  

CommonJS的模块规范

   CommonJS的模块主要由模块引用模块定义模块标识三部分组成。

  模块标识

  每个模块的模块ID都是唯一的,这是其引用的基础。它必须是以小峰命名的字符串,或者是文件的相对路径或绝对路径。

  Require(fs)//fs是内置模块,执行时会直接加载到内存中,没有路径标识。

  要求(。/moduleA)//导入当前目录的moduleA

  要求(./moduleB)//导入上一个目录的moduleB

  Require(C://moduleC)//绝对路径导入moduleC模块引用

  使用require()来引用模块。该方法接受模块ID作为参数,以便将模块的API引入到当前上下文中。

  Const fs=require(fs)//引入内置fs模块模块定义

  进口和出口都有。要将当前上下文中的方法或变量导出为模块,需要使用内置的module.exports对象,这是模块导出的唯一出口。

  CommonJS规范规定,在每个模块内部,模块变量代表当前模块。这个变量是一个对象,它的exports属性(即module.exports)是一个外部接口。加载一个模块实际上就是加载模块。

  //moduleA.js模块

  设moduleA={

  名称:“moduleA”

  }

  模块.导出={

  模块a

  }

  //moduleB.js模块

  //导入模块a

  const {modulea}=require()的功能。/modulea’)常见的模块如下:

  每个模块都有独立的上下文,模块中的代码独立执行,不会污染全局范围。一个模块可以多次加载,但只会在第一次运行,运行结果会被缓存。后续重新加载同一个模块会直接读取缓存的结果,加载module.cache中缓存的模块会按照代码顺序执行。

Node的模块实现

  节点导入模块需要经过三个步骤:路径分析-文件定位-编译执行:

  路径分析:根据模块标识分析模块类型。

  文件位置:根据模块类型和模块标识符找到模块的位置。

  编译执行:将一个文件编译成机器代码来执行,这需要一系列的转换。

  [推荐研究:《nodejs 教程》]

  模块分为内置模块和用户模块:

  内置模块:内置模块由node提供,已经编译成二进制可执行文件。Node执行时,内置模块会直接加载到内存中,所以我们可以直接引入。它的加载速度非常快,因为它不需要经过文件定位和编译来执行这两个步骤。

  文件:用js或C写的扩展模块,需要先编译成二进制机器码。它需要经过以上三个步骤。

  模块缓存

  无论是内置模块还是文件模块,node都会在第一次加载后缓存结果。下次加载同一个模块时,会先从缓存中搜索。如果可以找到,将直接从缓存中读取。缓存的结果是模块编译执行后的对象,是所有模块中速度最快的。

  路径分析

  路径分析基于模块标识符,模块标识符有以下类型:

  内置模块标识符,如fs、path等。不需要编译,节点运行时直接加载到内存中导入。相对路径模块ID:使用相对路径描述的文件模块的绝对路径模块ID:使用绝对路径描述的文件模块的自定义模块ID:通常是node_modules中的一个包,导入时不需要写路径描述。Node有一套算法可以找到它,是所有模块id中分析速度最慢的。文件定位

  文件定位主要包括文件扩展名分析、目录和包处理。如果在文件定位结束时没有找到文件,将抛出文件查找失败异常。

  文件扩展名分析

  由于可以在没有文件扩展名的情况下添加模块标识符,节点将按照以下顺序补充扩展名。js,json和。要尝试加载的节点。在尝试加载的过程中,需要调用fs模块来判断文件是否同步存在并被阻塞。所以为了提高性能,可以使用require()导入参数中带有文件扩展名的模块,这样会加快文件定位的速度。

  目录、包的处理

  当分析文件扩展名时,您可能会得到一个目录。此时Node会把它当作一个包,使用查找包的规则进行查找:在当前目录下查找package.json,获取其中定义的main属性指定的文件名,作为搜索入口。如果没有package.json,则默认设置目录中index的当前默认文件名,然后依次搜索index.js、index.json、index.node。

  编译执行

  编译和执行是模块导入的最后一步。节点将首先创建一个模块实例来表示当前模块。它具有以下属性:

  module.id模块的标识符,通常是带有绝对路径的模块文件名。具有绝对路径的module.filename模块的文件名。Module.loaded返回一个布尔值,该值指示模块是否已完成加载。Module.parent返回一个对象,该对象表示调用该模块的模块。Module.children返回一个数组,表示此模块要使用的其他模块。module.exports表示模块外部输出的值。通过文件位置获得的信息,Node重新加载文件并进行编译。对于不同的文件扩展名,加载方法是不同的:js文件:文件由fs模块同步读取,然后编译执行。节点文件:这是一个用C/C写的扩展文件,用dlopen()方法加载。json文件:被fs模块读取后,返回的结果被JSON.parse()解析。所有其他扩展都作为。js文件。每个加载的模块都将被缓存,并可以通过require.cache查看

  

使用ES-Module

  目前在node中使用ES-Module是一个实验函数,从8.5开始就支持了,执行时需要添加- experimental-modules参数。从12.17.0 LTS开始,实验模块已经被删除,现在它可以以两种方式使用:使用。mjs文件,而不是。或者在package.json中将类型指定为模块

  //package.json

  {

  名称: esm项目,

  版本: 1.0.0 ,

  main: index.js ,

  类型:模块,

  .

  }与CommonJS的模块机制相比,ES-Module最大的不同在于,ES-Module动态引用导出模块的变量和对象,在编译阶段就公开了模块的导入接口,因此可以进行静态分析;CommonJS-Module在运行时同步加载,输出是导出模块的浅层副本。另外,ES-Module支持加载CommonJS-Module,反之亦然。

  其次,Node规定一些CommonJS模块特有的内部变量不能在ES6模块中使用,因为ES-Module的顶层this指向undefined,CommonJS模块的顶层this指向当前模块,这些内部变量可以直接作为顶层变量使用。

  CommonJS的内部变量是:

  argumentsrequiremoduleexportsm _ _ filename _ _ dirname

总结

   node模块同步加载,只有在加载完成后才能执行以下操作。

  每个文件都是一个有自己范围的模块。在每个模块内部,module对象表示当前模块,其exports属性充当当前模块的导出接口。

  导入的模块是导出模块的浅表副本。

  有关编程的更多信息,请访问:编程视频!即CommonJS模块规范是什么?更多Nodejs模块机制分析详情请关注我们的其他相关文章!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: