一、Node的历史以及简介
- Node.js是一个基于Chrome JavaScript运行时环境 ,用来方便地搭建快速的 易于扩展的网络应用。Node.js借助事件驱动, 非阻塞I/O模型变得轻量和高效,非常适合 运行在分布式设备的数据密集型的实时应用。
- 是一个能够在服务器端运行JS的开放源代码、跨平台的JavaScript运行环境
- Node采用Google开发的v8引擎运行js代码,使用事件驱动、非阻塞和异步I/O模型等技术来提高性能,可优化应用程序的传输量和规模
Node的产生:Node产生的原因是为了帮客户解决Web服务器的高并发性能问题。传统服务器是多线程(对硬件的要求要高)的,一个请求就是一个线程,虽然有很多的线程可以提高效率,但是在I/O阶段就会阻塞执行从而导致性能整体不高。例如一个饭馆有很多的服务员,但是厨师慢,所以这就是影响整体性能的原因,数据库就是厨师,然后线程就是服务员。I/O的操作阻塞了线程的执行,所以像java一样多线程的语言性能就不是很好啦。v8引擎出现的时候满足了他关于高性能Web服务器的想象。单线程的,就是一个超级服务员(类似于高并发),不会因为I/O阻塞,异步执行I/O,异步是回调函数
二、优缺点
优点:
- 处理高并发场景性能更佳
- 斥候I/O密集型应用,特别是应用在运行极限是,CPU占用率仍然比较低,大部分时间是在做I/O硬盘的存读写操作
因为是单线程带来的缺点
- 不适合CPU密集型应用
- 只支持单核CPU,不能充分利用CPU
- 可靠性低,一但代码摸个环境崩溃,整个系统都会崩溃
应用场景:用户保单手机系统,基于web、canvas等多人联网游戏,基于web的多人实时聊天客户端、聊天室、图文直播
三、Node中运行JavaScript和浏览器中有什么不同
我们知道,JavaScript 的组成分为三个部分:
- ECMAScript
- DOM:标签元素相关的API
- BOM:浏览器相关的API
而 Node.js 的组成分为:
- ECMAScript。ECMAScript 的所有语法在 Node 环境中都可以使用。
- Node 环境提供的一些附加 API(包括文件、网络等相关的 API)
node的大致架构图
总的来说,JavaScript在浏览器中可以操作dom和bom,但在Node中可以操作整个计算机为我们所用
node中的全局对象
真正的全局对象
- global:类似于浏览器中的window
- console(跟浏览器中的不同,重新封装了)console.log():打印输入内容;console.clear():清空控制台;console.trace():打印函数的调用栈
- process:当前 Node.js 进程的信息并对其进行控制,常用process.env定义或者获取全局变量
- clearInterval、setInterval; clearTimeout、setTimeout
模块级别的全局对象
- __dirname: 获取当前文件所在的路径,不包括后面的文件名
- __filename: 获取当前文件所在的路径和文件名称,包括后面的文件名称
- exports: 导出模块,本质和module.exports是一个对象地址(如下所示)
- module:
module.exports用于指定一个模块所导出的内容,即可以通过require()访问的内容 - require: 用于引入模块、
JSON、或本地文件。可以使用相对路径引入本地模块或JSON文件,路径会根据__dirname定义的目录名或当前工作目录进行处理
module.exports 初始值为一个空对象 {}
exports 是指向的 module.exports 的引用,exports该对象将函数内部的局部变量或函数暴露到外面; require() 返回的是 module.exports 而不是 exports,最终所共享的结果是以module.exports所指向的对象为准。
也就是: exports = module.exports = {}, exports和module.exports都指向一个引用地址{},如果exports.name = 'xxx',那module.exports = {name:'yyy'},引用对象改变,两者又是同时指向一个对象,所以最终共享的结果是module.exports = {name:'yyy'};若module.exports.name = 'yyy',谁在后就共享谁;若共享的属性不一样都会共享出去。 exports只能通过.语法向外暴露变量(exports.xxx = "xxx");module.exports即可以通过点语法,也可以直接赋值一个对象(module.exports.xxx = "yyy"或module.exports = {xxx :"yyy")
原文链接:blog.csdn.net/muzidigbig/…
npm
npm是Node的模块管理器,主要分为三部分
网站
www.npmjs.com/ 开发者可以在该网站查找各种各样的包,以供使用
注册表(registry)
例如我们要查询 react 包的信息,可以访问https://registry.npmjs.org/react,就会看到 react 模块所有版本的信息。
命令行工具(CLI)
开发者可以使用该命令行工具和 npm 进行交互,包括包的安装,发布等
npm常用命令
- npm install
- npm run xxx
- npm config list
npm publish:发布自己开发的包到 npm 库中。npm get registry用于获取当前 npm 配置中的 registry 配置项的值。registry 配置项用于指定 npm 包的下载地址,如果未指定,则默认使用 npm 官方的包注册表地址npm set registrynpm config set registry <registry-url>命令,将 registry 配置项的值修改为指定的<registry-url>地址
注意npm run 的时候的执行过程
注意npm install 的执行过程
npm install 安装包的时候是扁平化的(广度优先算法)只有依赖相同版本号才会提升,不然不会提升
package.json的介绍和相关配置
执行npm init 便可以初始化一个package.json
main:项目的主入口文件路径,通常是一个 JavaScript 文件。(如果项目是npm包的话这个值必填并且在其他项目中引用的时候,就是通过这个属性来找到npm install时候的那个包:即npm包的入口文件)
peerDependencies:项目的同级依赖,适应于开发插件和npm包的项目中使用
package-lock.json的作用
package-lock.json 帮我们做了缓存,他会通过 name + version + integrity 信息生成一个唯一的key,这个key能找到对应的index-v5 下的缓存记录 也就是npm cache 文件夹下的
npmrc
npmrc 文件是 npm 的配置文件,共有三种级别,项目级>用户级>全局级。
内容格式:key=value。
通常我们会在项目中建立 .npmrc 文件,并对 registry 进行设置,防止开发者因为 registry 的原因而无法安装依赖。
npm 和 npx 区别
npx侧重于执行命令的,执行某个模块命令。虽然会自动安装模块,但是重在执行某个命令
npm侧重于安装或者卸载某个模块的。重在安装,并不具备执行某个模块的功能。
npx 的优势
- 避免全局安装:
npx允许你执行npm package,而不需要你先全局安装它。 - 总是使用最新版本:如果你没有在本地安装相应的npm package,
npx会从npm的package仓库中下载并使用最新版。 - 执行任意npm包:
npx不仅可以执行在package.json的scripts部分定义的命令,还可以执行任何npm package。 - 执行GitHub gist:
npx甚至可以执行GitHub gist或者其他公开的JavaScript文件。
npm包的发布和私服创建
通过创建项目开发业务代码之后在package.json文件中main属性中编写npm包的入口文件,之后登陆账号密码之后就执行npm public发布npm包即可
Verdaccio 是可以帮我们快速构建npm私服的一个工具
使用Verdaccio 创建一个私服仓库,然后执行发布和安装命令,主要发布命令
# 发布npm
npm publish --registry http://localhost:4873/
前端模块化和Node模块化
Node模块化
Nodejs 模块化规范遵循两套一 套CommonJS规范另一套esm规范
CommonJs
引入模块(require)支持四种格式
- 支持引入内置模块例如
httposfschild_process等nodejs内置模块 - 支持引入第三方模块
expressmd5koa等 - 支持引入自己编写的模块 ./ ../ 等
- 支持引入addon C++扩展模块 .node文件
ES模块化
ES模块化的时候要在package.json文件中设置type属性为module
import fs from 'node:fs'
// 默认是不支持加载json文件的,但高版本有试用版本了
import data from './data.json' assert { type: "json" };
console.log(data);
// 加载整个模块
import * as all from 'xxx.js' 可以异步加载
// 动态导入模块
if(true){ import('./test.js').then() }
CommonJs和ESM规范的区别
- CJS是基于运行时进行同步编译的(require可以在任何需要引入的地方引入),ESM是基于编译时的异步加载(只能在文件最上面使用import引入模块,不能在代码逻辑中使用,否则会报错)
- CJS是可以修改值的(输入的是一个值的拷贝,互相不受影响),ESM是只读的不可修改(输出的是值的引用)
- CJS是不支持tree shaking ,ESM因为在最开始编译的时候会有import加载哪个模块,可以tree shaking
- CJS顶层的this是指向这个模块本身的,ESM顶层this指向undefined
链接:juejin.cn/post/726404…
juejin.cn/post/684490…
前端模块化
前端模块化的前世今生:juejin.cn/post/700794…
我们说的 CommonJS 、AMD 、 CMD 等都只是社区比较认可的统一模块化规范(自己约定俗成的规范),但并不是官方(JS语言层面)的
2015年6月,ECMAScript2015 也就是我们说的 ES6 发布了,在语言标准的层面上,实现了模块化功能,而且实现的相当简单,旨在成为浏览器和服务器通用的模块化解决方案,其模块化功能主要由俩个命令构成:exports和import,export命令由于规定模块的对外接口,import命令用于输入其他模块的功能。ES6还提供了export default的命令。为模块指定默认输出。对应的import语句不需要大括号。这也更接近AMD的引用写法。