《深入浅出nodejs》学习笔记——第一、二章

码农天地 -
《深入浅出nodejs》学习笔记——第一、二章
第一章1. node是基于V8创建的一个轻量级Web服务器,并提供一套库2. 设计高性能Web服务器的几个要点:事件驱动、非阻塞IO3. 为什么是js

js无历史包袱、符合事件驱动、chromeV8的高性能,这三个要素促成了js作为node的实现语言

4. node名字由来

最初web服务器的想法变成了构建网络应用的基础框架,在它的基础上构建更多的东西,如服务器、客户端、命令行工具。node 为构建大型分布式应用程序提供基础设施;非常容易通过扩展来达成构建大型网络应用的目的。每个node进程都构成这个网络应用中的一个节点。

5. chrome和node的组件构成

js不再只限制于和浏览器中CSS和DOM打交道。

6. node特点:异步IO

Don't call me, I will call you.

通过异步方式,可以自然进行并行操作,每个调用间无须等待。

7. node特点:单线程

无法利用多核cpu、错误会导致整个应用退出、大量计算占用CPU导致无法继续调用异步I/O。Web Workers创造工作线程来计算解决了这个问题,Node采用了相同的思路,child_process

8. node特点:跨平台

平台架构层:libuv

9. 应用场景:I/O密集、CPU密集、分布式应用

上面也提及了,node擅长处理并行I/O;且有两个方式充分利用CPU

子进程方式编写C/C++扩展的方式第二章1. CommonJS规范

node借鉴CommonJS的Modules规范实现了一套非常易用的模块系统

2. CommonJS模块规范模块引用require模块定义exports.add = xxx,exports对象是唯一的导出的出口。模块标识:符合小驼峰的字符串、或以...开头的路径,或绝对路径。3. node模块

node并非完全按照规范实现,做了一定的取舍。

模块引入:

路径分析文件定位编译执行

模块分为两类:

node提供的核心模块,核心模块编译进了二进制执行文件,启动时就被直接加载进内存,省去了定位和编译两步,是最快的用户编写的文件模块,需要完整的3个步骤,较慢4. 缓存

node对引入过的模块都会进行缓存,缓存的是编译和执行后的对象。无论是核心还是文件模块,都是优先采用缓存的方式。核心模块的缓存检查先于模块缓存

5. 路径分析核心模块.,..开始的相对路径文件模块/开始的绝对路径文件模块非路径文件模块,如自定义模块6. 模块路径

模块路径生成规则,可通过module.paths查看。它是一个路径数组,

当前目录下的node_modules目录父目录下的node_modules目录向上直到根目录下的node_modules目录7. 自定义模块

特殊的文件模块,可能是一个文件或者包的形式,这类模块查找最费时,是所有方式中最慢的一种。

加载中,node会逐个尝试模块路径中的所有路径,直到找到目标。文件路径越深,耗时越多。

8. 文件定位

文件扩展名按,.js、.json、.node的次序尝试。如果是.node和.json,带上扩展名,会加快一点速度。

如果还未能找到对应的文件,却得到一个目录,node会将目录当做一个包来处理。node查找当前目录下的package.json,解析出包描述对象,从中取出main属性指定的文件名进行定位,如果文件名缺少扩展名,则进入扩展名分析。如果main属性指定文件名错误,或根本一开始没有package.json文件,node会将index作为默认文件名,一次查找index.js、index.json、index.node。

9. 文件编译

定位到具体文件,node会新建一个模块对象,根据路径进行载入并编译。不同文件扩展名,载入的方法也不相同。

js文件:通过fs模块同步读取文件后编译执行node文件:这是用C/C++编写的扩展文件,通过dlopen()方法加载最后编译生成的文件json文件:通过fs模块同步读取,用JSON.parse解析返回结果其他:都被当做js文件载入10. js模块编译

node对获取的js内容进行了头尾包装

(function(exports, require, module, __filename, __dirname) {
    文件内容
})
11. js核心模块代码以字符串形式存储在node命名空间中,是不可执行的,在启动node进程时,js代码直接加载进内存。

js核心模块和文件模块区别:

获取源码方式:从内存中加载/读取文件缓存执行结果:编译成功缓存到NativeModule._cache/Module._cache。12. 包的出现,是在模块的基础上进一步组织js代码;包由包结构和包描述文件两个部分组成。13. 包结构package.json 包描述文件bin 存放可执行的二进制文件的目录lib 存放js代码目录doc 存放文档目录test 存放单元测试用例目录14. 包描述文件package.json

必需字段

namedescriptionversionkeywordsmaintainers

其他

contributorslicensesdependenciesdevDependenciesrepositorymain: require引入包时,会优先检查这个字段,将其作为模块入口。如果不存在,则查找index.js、index.node、index.json文件binscript...15. npm install xxx

npm在当前目录创建node_modules目录,然后在node_modules目录下创建xxx目录,将压缩包接要到该目录中。通过require('xxx')即可引入该包。require在做路径分析时通过模块路径找到xxx所在的位置。

16. 全局模式安装npm install xxx -g

全局模式并不是将一个模块包安装为一个全局包的意思,它并不意味着可以从任何地方通过require来引用到它。

-g是将一个包安装位全局可用的可执行命令,它根据bin字段配置。将实际的脚本链接到node可执行的文件路径下。如

"bin": {
    "express": "./bin/express"
}
17. 发布包编写模块npm init注册npm仓库账号npm publish 文件夹:如npm publish .使用安装 npm install xxx

管理包权限

npm owner ls <package name>npm owner add <user> <package name>npm owner rm <user> <package name>18. npm包的评价标准良好的测试良好的文档 README、API良好的测试覆盖率良好的编码规范其他19. AMD异步模块定义Asynchronous Module Definition

模块的侧重点:

浏览器端js,瓶颈在于带宽,需要从网络加载代码

服务器端js,瓶颈在于CPU和内存资源,从磁盘中加载,很快。

如果前端模块采用同步的方式引入,用户体验造成很大的问题,AMD规范在前端应用场景中胜出。

define(id?, dependencies?, factory);
       
// example
define(function() {
  var exports = {};
  exports.sayHello = function() {
    // do something
  }
  return exports;
});
20. CMD

AMD是在声明模块的时候就指定所有的依赖,而CMD支持动态引入

define(function(require, exports, module) {
  // do something
})

在需要依赖模块时,随时调用require引入

21. 类库的兼容性

考虑类库运行在前后端不同的环境,类库开发者需要将类库代码包装在一个闭包中,保证前后端的一致性。

(function(name, definition) {
  // 上下文是否是AMD或CMD
  var hasDefine = typeof define === 'function';
  // 上下文环境是否为Node
  var hasExport = typeof module !== 'undefined' && module.exports;
  if (hahsDefine) {
    define(definition);
  } else if (hasExport) {
    module.exports = definition();
  } else {
    // 将模块执行结果挂在window变量中,浏览器this指向window对象
    this[name] = definition();
  }
})('hello', function() {
  var hello = function() {...};
  return hello;
});
特别申明:本文内容来源网络,版权归原作者所有,如有侵权请立即与我们联系(cy198701067573@163.com),我们将及时处理。

Tags 标签

加个好友,技术交流

1628738909466805.jpg