当前位置: 首页 > 后端技术 > Node.js

重写Node基础(阅读《Node.js 来一打C++扩展》)

时间:2023-04-03 12:17:46 Node.js

NPM的作用:Node.js程序依赖包的发布、管理和安装。CommonJS规范requirerequire是一个函数,其参数是一个模块标识符,其返回值是被引用的模块暴露给外部用户的内容。说白了:一个模块定义文件module1.jsmodule.exports={a:1,f:function(){console.log('f');}}引用模块module1.js的文件letm1=require('module1.js');console.log(m1);//{a:1,f:?}模块的上下文在每个模块中,有以下东西:requirefunctionexportsobject,挂载在这个对象上的东西会暴露给外界。module对象包含了一些模块本身的信息,比如ID![moduleobjectinstance]()注意:exports对象实际指向的是module.exports的引用,如果你替换掉module.exports的引用。参考文献不一样。如果不了解这个问题,在使用世纪城的过程中可能会遇到一些难以预料的问题。ModuleID模块ID是一个字符串,理论上应该是小驼峰命名法,或者以“.”、“..”、“/”开头的路径。如果模块标识是文件路径,理论上是不需要在文件名上加上“.js”后缀的。未指定的约定有些机制可以在符合CommonJS规范的情况下随意实现。之所以这么说,是因为其实这些东西也是构建一个完整模块所必需的,只是CommonJS并没有严格定义这些东西,理论上只要达到设定的目标就可以了。模块的存储方案,模块的内容可以存储在数据库、文件系统、工厂函数甚至链接库中;模块加载器加载时可以支持PATH环境变量寻址,也可以不支持,对Node没有强制限制。js模块Node程序通常由模块一个一个组装而成。这些模块的可能形式:js文件、json文件、C++module.node的二进制文件。这些模块是通过require函数导入的。Node中的模块查找Node中的模块分为两类:核心模块和文件模块。核心模块存在于Node源码中,属于Node内置模块。主要是一些基础模块,比如:fs、http等。找到它们非常简单。如果require中的模块标识与这些核心模块的名称匹配,则直接返回这些核心模块导出的内容。文件模块是需要通过搜索文件得到的模块。这些模块是由第三方开发人员编写的程序,并不是Node本身的一部分。它们是您在编写Node程序(在Node.js上运行的程序,而不是Node.js自身)时导入的文件。文件模块可以分为第三方模块和项目模块。如果传入的require函数是一个文件路径,一般可以认为是一个项目模块。对于项目模块,如果在路径中指定了特定文件,则直接导入。如果路径是目录,首先检查是否有package.json文件,如果存在并且package.json中定义了main属性,则根据main属性的值查找模块的入口文件,如果没有,则依次搜索目录index.js、index.json、index.node。如果在require函数中传入一个非路径值,就可以认为是第三方模块。Node也有一套查找第三方模块的规则。当前文件的node_modules目录(require函数所在的文件);当前文件父目录下的node_modules下,如果没有则继续上层目录,直到根目录下的node_modules;找到对应的模块后,其实等于获取了模块的文件PATH后,会去查找模块的入口文件(查找规则同项目模块),得到的内容模块导出。模块缓存Node会缓存需要的模块,也就是说,如果一个模块已经被加载,当其他模块引用该模块时,Node会直接读取缓存中的内容并返回。Node的包机制包描述文件package.json的主要内容之前已经写好了。包目录结构package.json在根目录下二进制文件在bin目录下JavaScript源码在worship目录下文档在doc目录下单元测试文件在test目录下Node.js/NPMNPM下的包(Node.js包管理器)。NPM中有一个包信息描述文件——package.json。这个文件会记录这个包的其他依赖。而它的第三方模块会放在node_modules目录下,这就导致一些开发者将这个目录作为项目的一部分提交到git仓库,但我们其实并不推荐这样做。因为项目运行时需要用到node_modules提供的文件,而且通常它的内容会比较多。我们可以根据pacakge.json文件的描述,在运行项目之前安装这些依赖(一般是通过npm命令npminstall)。如果您对第三方模块的源代码进行了任何更改,建议的方法是在项目初始化时或其他适当的时候进行hack。npm下的package.json文件是根据CommonJS定义的包描述文件实现的。但有些地方不一样。在这一点上,我们需要弄清楚。NPM在NPM中,NPM2和NPM3是有区别的。NPM2的依赖安装路径是嵌套的,适用于Node.js工具和后端开发。在npm2中,如果不同的package使用了同名不同版本的第三方模块,那么这个模块的两个版本都放在各自引用的node_modules目录下,互不干扰。node_modules----bar----node_modules----foo@1.0.0----baz----node_modules----foo@2.0.0而在NPM3中,依赖的安装路径变平了风格。所有的第三方依赖都放在根目录下的node_modules中。这种方法适用于前端项目:需要优化到代码空间占用小,打包分析等,也解决了Windows下文件路径不允许太长的问题。嵌套只有在遇到冲突时才会发生。NPM3的思想:尽可能扁平化你的依赖。CNPMCNPM是阿里巴巴集团Node.js团队开发的一套速度更快的NPM工具。比npm更快的不仅是使用国内的镜像,而且安装过程中会在node_modules/.npminstall目录下缓存一些包,然后将依赖目录连接到对应的路径下。也就是说,在实际安装过程中,同一个版本的包只有一个实体,类似于npm3。ChromeV8Node.js使用ChromeV8作为Javascript解释器。V8是一个高效的JavaScript引擎,区别于其他JS引擎:JIT编译垃圾回收内向缓存隐藏类JIT编译JIT编译、Just-In-Time编译、即时编译。编译后的输出是机器语言,而不是字节码。垃圾收集V8的垃圾收集器借鉴了JavaVM精确的垃圾收集管理,其垃圾收集机制的效率相当高。如果内联缓存(InlineCache)访问过a.b,那么再次访问a.b时,不会再寻址哈希表,因为V8已经缓存了这个属性的偏移量,不需要再计算地址的偏移量再次。移位。隐藏类TODO:隐藏类的具体机制需要进一步查询。V8引擎比较高效的机制主要是内联缓存和隐藏类。V8引擎遵循ECMAScript标准。Node.js会随着V8的更新升级自己的代码。libuvlibuv是一个专注于异步I/O的跨平台类库。最初由Node的创始人RyanDahl为Node编写。只要是为Node开发的,其他项目也可以支持。libuv中的一个重要概念是事件循环。libuv的一些特性是基于epoll/kqueue/IOCP/eventports实现的万能事件循环;异步TCP和UDP套接字,异步DNS解析,异步文件,文件系统操作,文件系统事件,ANSI转义码控制TTY使用UNIX域套接字word或namedpipe实现的socket共享IPC子进程线程池信号(Signal)处理高精度时钟线程和同步元PS:不同平台有不同的异步机制(如epoll、IOCP等),libuv基于此实现跨平台事件循环。另外,libuv接口简洁、灵活、易用。Node中的事件循环直接使用了libuv的事件循环。Node中其他的依赖http-parser,一个用C实现的HTTP消息解析器,可以解析HTTP协议的请求数据和返回数据。OpenSSL安全套接字层协议库。SSL(SecureSocketLayer)可以提供网络上的保密传输。用于加密HTTP协议。zlibzlib是一个提供数据压缩功能的库。IDE大神编辑器大神VIM/NeoVIMEmacsSublimeTextVisualStudioCodeAtomVisualStudionode-gypnode-gyp是Node.js下的C++扩展构建工具。基于GYP(GeneralYourProjects)工作,GYP是Google的一套构建工具。node-gyp需要一些依赖才能工作。UNIX系列平台下:pythonmakeC++CompilationToolkit(GCC)macOS下:xcodeWindows下,VisualStudio或者使用VisualC++BuildTools(比较轻量级)。