CommonJS一般只将JS文件和JSON文件视为有效模块(require只支持导入js或json文件),而ES6将任何文件都视为模块(import path语法支持导入任何类型文件)
模块三要素的区别
1、CommonJS将模块包装函数的函数作用域 作为 模块独立作用域,是运行时确定的。
由于ES6模块是在编译时(静态分析时)确定的,此时没有全局变量或模块变量之分,变量是运行时产生的,所以也不会产生变量污染
2、导出导入
CommonJS模块的导出module.exports的是对象,
ES6模块的导出接口export是静态分析阶段的符号链接
访问CommonJS模块的导出对象module.exports,其实访问的是对应模块导出数据的浅拷贝,
对于简单值来说,和原模块无关,对于引用值来说,和原模块有关。
访问ES6模块的导出接口export,其实是访问的对应模块的实时数据,无论是简单值还是引用值都和原模块有关
导入导出语法区别
CommonJS模块导入使用require函数,导出使用module.exports对象
ES6模块导入使用import path 或者 import { somename as anyname} from path 或者 import anyname from path
导出使用export 或 export {} 或 export default
ES6的导入导出语法更复杂一点,CommonJS的简单一点
模块代码的执行时机
CommonJS模块代码运行是在模块首次被require时,
ES6模块代码运行是在模块首次被import时
深入了解请看下面关于模块化的总结
(1条消息) 随笔-深入理解ES6模块化(三)_qfc_128220的博客-CSDN博客 随笔-深入理解ES6模块化(三)_qfc_128220的博客-CSDN博客")
Node.js的软件包管理器(npm)
啥是软件包
基于Node.js开发的应用程序都可以看成一个Node Package,Node package中通常都有一个包描述文件package.json。
啥是软件包管理器
npm (Node package manage),即软件包管理器,我们下载Node.js时,会默认捆绑下载npm。
它是一个命令行工具。
npm 可以通过命令行管理Node应用程序依赖的第三方软件包,比如下载、删除、更新、查看第三方软件包。
npm 下载和更新第三方软件包的默认地址是 npmjs.com,
npmjs.com 是一个Node软件包管理网站,开发者可以将自己开发Node软件包共享到该网站,也可以从该网站下载Node软件包。
认识package.json
一个Node软件包的项目根目录下必须有一个package.json文件,该文件用于记录当前软件包的一些基本信息。
我们可以在Node软件项目根目录下使用npm命令,生成一个由用户自定义的package.json
npm init
或者加上 --yes 或简写 -y 参数 来自动生成一个采取默认定义的package.json
npm init --yes
npm init -y
接下来,我们看下package.json包含哪些信息
npm init 生成的package.json只包含一些基本的软件包信息:
name | 软件包名字,或者项目名字 |
version | 软件包版本号 |
description | 软件包描述 |
main | 软件包入口文件 |
script | 软件包的自定义命令 |
keywords | 软件包的搜索关键词 |
author | 软件包的作者信息 |
license | 软件包的许可证信息,ISC表示开源 |
这些信息都是比较重要的信息,而其中常手动改的是 main 和 script
main用来指定当前软件包的入口文件,作用有两个:
1、我们可以通过查看一个软件包根目录下的package.json中的main配置,快速得知当前软件包的入口,而不需要分析代码
2、package.json中main配置 是 模块查找规则 的重要一环。比如 node test 或 require(‘test’),会先去当前目录下找test.js,再找test.json,如果都没有再找test文件夹,如果有,就继续找package.json中main配置的入口文件,如果有,入口文件会被当成找到的模块被运行或被引入。
script是用于配置当前软件包一些常用命令的npm run简写的:
比如上面可以使用 npm run serve 代替npx vue-cli-service serve。
下载第三方软件包
使用 npm install packagename 或者简写 npm i packagename 即可下载指定的软件包,命令执行完后,本地Node应用程序会发生如下变化:
1、下载软件包会被保存在项目根目录的node_modules文件夹下,如果没有node_modules文件夹,则会自动生成
2、package.json会发生变化,配置项多出一个 dependencies ,其中保存着下载的软件包名字 和 软件包版本号 组成的键值对
3、项目根目录下会多出一个 package-lock.json文件,该文件会记录下载的软件包的下载地址,以及该软件包依赖的其他软件包的下载地址
项目依赖和开发依赖
我们下载的第三方软件包有两种用途:
1、用于项目中业务逻辑的开发,比如 formidable,express
2、用于辅助开发者高效开发,和项目业务无关,比如一些常用的命令行工具nodemon,eslint,
我们有必要将他们区分开来,原因是:
项目上线后,其实并不需要和项目业务无关的第三方软件包,只需要和项目业务有关的第三方软件包。
但是项目开发过程中,又需要协同开发,即至少要保证大家使用一样的开发工具。
而Node应用程序考虑到了这一点,在项目的package.json将依赖的第三方软件包分为了两类:开发依赖 和 项目依赖
开发依赖的第三方包 会被保存在 dev-dependencies中
项目依赖的第三方包 会被保存在 dependencies中
而我们只需要在下载第三方包的时候,指定一些参数即可实现分类:
npm i --save packagename 即下载时指定–save,npm就自动将下载的包添加到package.json的dependencies中,即项目依赖
简写形式是:npm i -S packagename
最简形式是:npm i packagename
目前 npm i packagename 默认会将下载的第三方包当成“项目依赖”
npm i --save-dev packagename 即下载时指定 --save-dev,npm就自动将下载的包添加到package.json的dev-dependencies中,即开发依赖
简写形式时:npm i -D packagename
本地下载和全局下载
我们使用 npm i packagename时,默认将第三方软件包下载到 项目根目录下的node_modules文件夹中。
此时该第三方包只在当前项目中起作用,我们称这种下载叫本地下载。
如果我们本地有多个Node项目,如果每个Node项目都依赖一些相同的第三方包,则为每一个Node项目都下载一遍,会造成内存浪费。此时就需要将多个项目都需要的公共包,下载到全局下,即所有项目都可以访问到的地方,避免内存浪费。此时下载叫做全局下载。
全局下载只需要添加一个-g参数
npm i -g packagename
如果想知道全局下载的软件包的存放路径,则可以使用命令
npm root -g
需要注意的是:
全局下载的Node软件包如果是命令行工具,则其命令会被自动被注册为系统变量,在任意目录下都可用。
而本地下载的命令行工具Node软件包,由于其命令不会被自动注册为系统变量,所以无法在任意目录下直接使用其命令,只能通过npx命令来调用
例如,只在项目中安装nodemon(保证全局下没有nodemon,使用npm list -g查看)
此时nodemon命令不会被自动注册为系统变量,所以无法在任意目录下使用nodemon命令。需要借助npx命令借调nodemon命令
为什么下载到全局的node软件包的命令会自动注册为系统变量呢?
1、安装好Node.js后,会自动将node_global目录加入系统变量Path中
2、我们下载全局软件包时,会自动存放在node_global下
3、如果下载的全局软件包是命令行工具,则会将cmd命令文件放到node_global目录下,这就保证了如nodemon.cmd这样的命令可以在任意目录下使用
那么我们是否可以将所有开发依赖的软件包都从项目本地,转移到全局呢?
一般来说不会这样搞,将项目本地的node包单分出一个开发依赖,其实就是为了团队之间的协同,如果大家都自己搞自己的,可能对于新人不太友好。
软件包的语义化版本
在package.json中有三个地方存在软件包的版本号信息
1、package.json的version配置
2、package.json的dependencies配置
3、package.json的dev-dependcies配置
其中
version 版本号,指的是当前项目的版本号,由我们控制版本的升级
而dependencies和dev-dependencies中的版本号,是当前项目依赖的第三方Node包的版本号,不由我们控制。
通过上图,我们可以发现版本号由三部分组成,即 major.minor.patch
解释 | 升级时机 | |
major | 主要版本号 | 已有需求发生改变,并且改变了已有功能 |
minor | 次要版本号 | 已有功能不变,开发了新需求的功能 |
patch | 补丁版本号 | 修复了已有功能的bug,需求不变 |
分析一下,patch和minor升级是向低版本兼容的,而major升级不向低版本兼容。
所以,我们项目依赖一个第三方包后,一般都需要锁定major版本,防止更新包后,新版本的第三方包代码不向下兼容。
此时就需要给版本号加入语义化。如上图中 package.json的 dependencies 依赖的第三方包的版本号前面有个^,这就是语义化符号。
^major.minor.patch | 表示锁定major版本,只能升级minor和patch版本 |
~major.minor.patch | 表示锁定major和minor版本,只能升级patch版本 |
major.minor.patch | 表示锁定major,minor,patch版本,不让升级 |
下载指定版本号的第三方软件包
前面我们下载第三方软件包时,都是只指定了包名,没有指定具体版本号,此时下载就是第三方包的最新版本,即
npm i packagename
下载的时packagename包的最新版本。
但是有时候最新版本并不稳定,所以我们一般下载比较稳定的老版本,此时就需要指定版本号
npm i packagename@major.minor.patch
但是我们可能并不知道对应第三方包有哪些版本,此时需要借助命令查询第三方包历史版本列表
npm view packagename viersions
更新第三方软件包
更新项目依赖的第三方软件包时,需要注意:
1、当前依赖的第三方软件包是否过时了
2、当前依赖的第三方软件包是否被锁定
通过命令 npm outdate 就可以查看当前项目依赖的第三方包是否存在过时的,如果有会全部列出来
我们发现 eslint和nodemon都过时了,且nodemon最新版本是2.0.15,但是只能升级到1.19.4。而eslint最新版本是8.6.0,但是只能升级到1.10.3,即当前版本,即eslint无法再升级了。
再看这两个包的版本锁定情况
发现都被锁死在了major版本,即major版本不允许升级,minor、patch版本可以升级。而这也是导致eslint和nodemon无法升级到最新版本,只能升级到major为1的最高版本。
更新版本时,使用如下命令可以更新所有过时的第三方包到锁定的最高版本,而不是最新版本
npm update
而 npm outdate 和 npm update 命令加上-g参数,就可以查看和更新全局下的过时Node包
删除第三方软件包
通常使用命令
npm uninstall packagename
来删除项目本地指定的第三方软件包,
或者使用其简写命令
npm un packagename
加上 -g 参数就可以删除全局下的第三方软件包
查看第三方软件包元数据
一个第三方软件包,包含了各种元数据,比如包名,最近更新时间,历史版本列表,作者,
这里我们可以使用命令
npm view packagename
来查看指定软件包的所有元数据信息
也可以加入元数据配置项参数,来查看特定元数据信息,如命令
npm view packagename views
获取依赖的所有第三方软件包,及其依赖包列表
比如,获取项目本地下载的所有第三方软件包使用命令
npm list
加上 -g 参数表示,获取全局下载的所有第三方软件包
npm list -g
但是npm list目前只能查看被依赖的第三方软件包本身,无法查看第三方软件包依赖的包,这里提供了 --depth num,来指定查看的层级,默认npm list相当于 npm list --depth 0
npm list -g --depth 1
项目直接依赖包和项目间接依赖包
我们项目下载了一个第三方软件包,比如mongoose,那么它就成为了我们项目的一个依赖包。
但是mongoose本身也是一个项目,它也有很多依赖包,也需要被下载。
即:我们下载mongoose包,则会自动下载mongoose包的依赖包。其中mongoose就是当前项目直接依赖包,mongoose的依赖包就是当前项目间接依赖包。它们都是当前项目必须的。
上面查看,当前项目的依赖包只有一个mongoose,但是实际上,当前项目根目录node_moudules文件夹中下载的第三方包包含:
可以发现 “项目直接依赖包” 和 “项目间接依赖包” 都会被存放在 项目的node_modules文件夹下
这就会造成一个问题:
比如项目下载 A包,A包依赖于 Z@1.0.0包,项目又下载了B包,B包依赖于Z@2.0.0包
那么按照上面下载规则,A,B,Z包都会放在项目的node_modules文件夹下,那么Z包是否会发生冲突覆盖?
答案:不会,因为 项目间接依赖包 下载遵循如下规则
项目直接依赖包 会被直接下载到 项目的node_modules下,
而项目间接依赖包 下载前,会检查当前项目node_modules下是否已有该包,
没有的话,则将项目间接依赖包 下载到 项目的node_modules下,
有的话,则将 项目间接依赖包 下载到 项目直接依赖包 的node_modules下
这样就避免了项目间接依赖包之间发生冲突。
那么为什么不直接将 项目间接依赖包 直接下载到对应的 项目直接依赖包的node_modules文件夹下呢?
因为,项目直接依赖包 之间 存在大量重复的 依赖包,如果将项目间接依赖包 直接 存放再 项目直接依赖包下,可能会造成大量的重复包下载,浪费内存。
npm常用命令总结
增 |
|
| ||||||||||||
删 | npm un package |
| ||||||||||||
改 |
|
| ||||||||||||
查 |
|
|
项目node_modules目录是否需要提交git
答案:不需要,项目node_modules存放的都是依赖第三方软件包代码,体积很大,如果上传到git仓库的话,很浪费时间。
所以我们一般在项目根目录的.gitignore文件中设置忽略 node_modules/ 的提交
那么项目发布到npmjs.com后,其他人下载后,如何获取项目的node_modules依赖包。
当我们项目下载依赖包后,依赖包的版本号和下载地址都保存在了项目根目录下的package-lock.json中,当其他人下载项目后,使用npm i package会自动根据软件包的package-lock.json去下载对应的依赖包。
项目开发过程中,拉取git仓库代码到本地,也是没有node_modules的,此时只需要 npm install 即可自动根据package-lock.json快速下载依赖包
发布软件包和更新软件包版本号以及撤回软件包
当我们项目开发完成后,需要共享到npmjs.com时,即表示发布软件包,发布软件包需要先登录npmjs.com,使用命令
npm login
登录到npmjs.com后,再使用如下命令来发布项目到npmjs.com的个人空间中
npm publish
当项目发生版本更新后,可以使用如下命令来更新项目的版本号,即package.json中的version
npm version major // 更新major版本
npm version minor // 更新minor版本
npm version patch // 更新patch版本
当项目发布错误,或者版本存在重大Bug时,需要撤回已发布的版本时,如果在24h内,则可以撤回,24h后不可撤回,撤回成功后,24h后才能重新发布,且重新发布的包的名称和版本号都要修改
npm unpublish package --force
更改npm镜像地址
在国内更改npm镜像地址是一个有必要的操作,因为默认按照的npm的地址是npmjs.com,这个网址是国外网站,下载上传速度很慢。而npm的地址是npm的配置信息之一。我们可以查看npm的所有配置,使用如下命令
npm config list
可以使用如下命令获取特定的npm配置信息
npm config get registry
可以使用如下命令设置特定的npm配置信息
npm config set registry https://registry.npm.taobao.org/
可以使用如下命令删除特定的npm配置信息
npm config delete registry
可以使用如下命令修改特定npm配置信息
npm config edit registry https://registry.npmjs.com/
而npm的配置信息都保存在一个文件中,我们可以通过如下命令获取到对应文件的地址
npm config get user
Node.js的异步编程(异步编程方案+Event Loop)
异步原理
Node.js 是基于 Chorme v8引擎开发的JS运行环境,所以Node.js生来支持ECMAScript语法。
而我们知道JavaScript代码是单线程运行的,为了提高JS代码执行效率,不让JS代码被某些不依赖于CPU的操作所阻塞,如I/O操作,出现了很多事件驱动的,基于回调函数的Node APIs。
“事件驱动,基于回调” 的 意思是:当 … 时候,JS单线程再来执行… 回调。
这就是JS的异步编程原理。
异步任务串行的实现
小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Web前端开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注:前端)
更多面试题
**《350页前端校招面试题精编解析大全》**内容大纲主要包括 HTML,CSS,前端基础,前端核心,前端进阶,移动端开发,计算机基础,算法与数据结构,项目,职业发展等等
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
的,基于回调函数的Node APIs。
“事件驱动,基于回调” 的 意思是:当 … 时候,JS单线程再来执行… 回调。
这就是JS的异步编程原理。
异步任务串行的实现
小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Web前端开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-Kb6d0qPO-1710829153353)]
[外链图片转存中…(img-dBNyjL9i-1710829153354)]
[外链图片转存中…(img-sdQPbU6k-1710829153354)]
[外链图片转存中…(img-BiQGrLQP-1710829153354)]
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注:前端)
[外链图片转存中…(img-SQakgO1x-1710829153355)]
更多面试题
**《350页前端校招面试题精编解析大全》**内容大纲主要包括 HTML,CSS,前端基础,前端核心,前端进阶,移动端开发,计算机基础,算法与数据结构,项目,职业发展等等
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
[外链图片转存中…(img-FzzdpCdp-1710829153355)]