如果你是一个前端程序员,你不懂得像PHP、Python或Ruby等动态编程语言,然后你想创建自己的服务,那么Node.js是一个非常好的选择。如果你熟悉Javascript,那么你将会很容易的学会Node.js。
Node.js 是一个基于 Chrome V8 JavaScript 引擎 构建的开源、跨平台运行时环境。V8 引擎是即 Google Chrome 的核心。这使 Node.js 的性能非常出色。V8引擎允许开发者使用 JavaScript 编写服务器端代码,而不是仅仅局限于浏览器中的前端开发。
Node.js 是运行在服务端的 JavaScript,是一个事件驱动I/O服务端JavaScript环境,基于Google的V8引擎,V8引擎执行Javascript的速度非常快,性能非常好。
NodeJS官网:https://nodejs.org/zh-cn
打开官网中的下载页面,选择一个合适的版本下载安装包,然后双击安装:
安装过程:点击下一步…下一步…默认安装即可。
NodeJS历史版本下载:https://nodejs.org/dist/
安装完毕后,打开cmd窗口,输入node -v查看node的版本。
我们现在做个最简单的小例子,演示如何在控制台输出,创建文本文件demo01.js,代码内容:
1 2 3 |
var a=1; var b=2; console.log(a+b); |
我们在命令提示符下输入命令
1 |
node demo01.js |
创建文本文件demo02.js
1 2 3 4 5 |
function add(a,b){ return a+b; } var c=add(100,200); console.log(c); |
命令提示符输入命令
1 |
node demo2.js |
运行后看到输出结果为300
模块是Node.js 应用程序的基本组成部分,文件和模块是一一对应的。换言之,一个 Node.js 文件就是一个模块,这个文件可能是JavaScript 代码、JSON 或者编译过的C/C++扩展。
将一个复杂的程序文件依据一定规则(规范)拆分成多个文件的过程称之为模块化,其中拆分出的每个文件就是一个模块 ,模块的内部数据是私有的,不过模块可以暴露内部数据以便其他模块使用。
创建文本文件demo03_01.js
1 2 3 |
exports.add=function (a,b){ return a+b; } |
创建文本文件demo03_2.js
1 2 3 4 |
// 导入demo03_1模块,类似于Java中的对象 var demo= require('./demo03_01'); // 通过"对象名"调用方法 console.log(demo.add(400,600)); |
我们在命令提示符下输入命令
1 |
node demo03_02.js |
结果为1000
Node.js 作为一个 JavaScript 的运行环境,其官方提供了非常多的的内置模块,这些内置模块就和Java中的核心API一样,为NodeJS提供了很多基础功能,我们可以通过require()将这些模块导入到当前的JS文件中。
使用示例:
1 2 3 4 5 6 7 8 9 10 |
// 导入fs模块 const fs = require('fs'); fs.writeFile('./test01.txt', '学而时习之,不亦说乎', err => { //如果写入失败,则回调函数调用时,会传入错误对象,如写入成功,会传入 null if (err) { console.log(err); return; } console.log('写入成功'); }); |
fs模块是nodejs中关于文件操作的模块。
语法:
使用示例:
1 2 3 4 5 6 7 8 9 10 11 |
// 导入fs模块 const fs = require('fs'); var str = "北冥有鱼,其名为鲲。鲲之大,不知其几千里也。" fs.writeFile('./test01.txt', str, err => { //如果写入失败,则回调函数调用时,会传入错误对象,如写入成功,会传入 null if (err) { console.log(err); return; } console.log('写入成功'); }); |
使用示例:
1 2 3 4 5 6 7 8 9 10 11 12 |
//导入 fs 模块 const fs = require('fs'); // 读取的是字节 fs.readFile('./test01.txt', (err, data) => { if(err) throw err; console.log(data); }); // 安装编码来读取 fs.readFile('./test02.txt', 'utf-8',(err, data) => { if(err) throw err; console.log(data); }); |
1 2 3 4 5 |
const fs = require('fs'); fs.unlink('./test01.txt', err => { if(err) throw err; console.log('删除成功'); }); |
使用示例:
1 2 3 4 5 6 7 8 9 10 11 |
const fs = require('fs'); // 创建文件夹 fs.mkdir('./a1', err => { if(err) throw err; console.log('创建成功'); }); //递归创建 fs.mkdir('./aa/b1/c1', {recursive: true}, err => { if(err) throw err; console.log('递归创建成功'); }); |
使用示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
const fs = require('fs'); //删除文件夹 fs.rmdir('./a1', err => { if(err) throw err; console.log('删除成功'); }); //递归删除文件夹 fs.rmdir('./aa', {recursive: true}, err => { if(err) { console.log(err); } console.log('递归删除') }); |
http模块是nodejs中有关于http协议的模块。
(1)创建HTTP服务:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// 1. 导入http模块 const http = require('http'); /** * 2. 创建http服务 * request:请求对象 * response:响应对象 */ const server = http.createServer((request, response) => { response.end('Hello HTTP server'); }); // 3. 监听端口, 启动服务 server.listen(8000, () => { console.log('服务已经启动, 端口 9000 监听中...'); }); |
打开浏览器,访问:http://localhost:8000
(2)request对象
常用方法及属性:
含义 | 语法 |
---|---|
请求方式 | request.method |
协议和版本 | request.httpVersion |
请求路径 | request.url |
URL 路径 | require(‘url’).parse(request.url).pathname |
URL 查询字符串 | require(‘url’).parse(request.url).query |
请求头 | request.headers |
请求体 | request.on(‘data’, function(chunk){}) request.on(‘end’, function(){}); |
使用示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
// 1、引入http模块 const http = require("http"); const url = require('url') // 2、建立服务 const server = http.createServer((request, response) => { // 设置响应类型 response.setHeader("Content-Type", "text/html;charset=utf-8") // 获取完整的请求路径(带请求参数) var requestUrl =url.parse(request.url).pathname; // 获取查询字符串 var params = url.parse(request.url).query; response.write(`<hr> 请求方式: ${request.method}`); response.write(`<hr> 协议和版本: ${request.httpVersion}`); response.write(`<hr> 请求路径: ${request.url}`); response.write(`<hr> URL 路径: ${requestUrl}`); response.write(`<hr> URL 查询字符串: ${params}`); response.write(`<hr> 请求头: ${JSON.stringify(request.headers)}`); response.write("name:" + params.name); if (request.url == "/register" && request.method == "GET") { response.end("<hr> welcome to register..."); } else if (request.url == "/login" && request.method == "GET") { response.end("<hr> welcome to login..."); } else { response.end("<h1>404 Not Found</h1>") } }) // 3、监听端口 server.listen(8000, () => { console.log('服务启动中....'); }) |
打开浏览器,访问:http://localhost:8000/register?username=xiaohui
(3)response对象
常用方法及属性:
作用 | 语法 |
---|---|
设置响应状态码 | response.statusCode |
设置响应状态描述 | response.statusMessage |
设置响应头信息 | response.setHeader(‘头名’, ‘头值’) |
设置响应体 | response.write(‘xx’) response.end(‘xxx’) |
使用示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
require('http').createServer((request, response) => { //获取请求的方法已经路径 let {url, method} = request; // 设置响应类型 response.setHeader("content-Type", "text/html") if (method == "GET" && url == "/index.html") { // 通过fs模块读取文件(同步读取) let data = require('fs').readFileSync('./index.html'); response.statusCode = 200; response.end(data); } else { let data = require('fs').readFileSync('./404.html'); response.statusCode = 404; response.end(data); } }).listen(8000, () => { console.log('8000端口正在启动中....'); }) |
访问:http://localhost:8000/index.html
npm全称Node Package Manager,他是node包管理和分发工具。我们可以把NPM理解为java中的Maven。我们通过npm可以很方便地下载js库,管理前端工程。最近版本的node.js已经集成了npm工具,在命令提示符输npm -v 可查看当前npm版本。
NPM官网:https://www.npmjs.com/
NPM官方的管理的包都是从 http://npmjs.com下载的,但是这个网站在国内速度比较慢。这里推荐使用淘宝 NPM 镜像 ,淘宝 NPM 镜像是一个完整 npmjs.com 镜像。
设置镜像地址:
1 2 3 4 5 6 |
#经过下面的配置,以后所有的 npm install 都会经过淘宝的镜像地址下载 npm config set registry https://registry.npmmirror.com #查看npm配置信息 npm config list # 查看镜像源 npm config get registry |
命令 | 介绍 |
---|---|
npm init | 初始化工程 |
npm init -y | 可以跳过向导,快速初始化工程 |
npm install | 简写npm i,自动下载package.json中dependencies中全部的依赖。 |
npm install 包名 | 简写npm i 包名,下载指定包 |
npm install --save 包名 | 简写npm i -S 包名,下载并保存依赖项(package.json中dependencies) 5.0.0版本之后的npm会自动保存到dependencies |
npm uninstall 包名 | 简写npm un 包名,只删除,如果有依赖项会依然保存 |
npm uninstall --save 包名 | 简写npm un -S 包名,删除的同时也会将依赖信息删除 |
npm help | 查看使用帮助 |
npm 命令 --help | 查看对应命令的使用帮助,例如我忘记uninstall的简写,那么我可以输入npm uninstall --help |
使用npm init命令可以把当前文件夹初始化成一个“包”,即一个标准的nodejs工程
建立一个空文件夹,在命令提示符进入该文件夹 执行命令初始化
1 2 |
npm init npm init -y # 全面使用默认值来初始化项目 |
按照提示输入相关信息,如果是用默认值则直接回车即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
C:\Users\Admin\Desktop\dfxt\dfxt_day02\web\NodeJSDemo\demo04_npm>npm init This utility will walk you through creating a package.json file. It only covers the most common items, and tries to guess sensible defaults. See `npm help init` for definitive documentation on these fields and exactly what they do. Use `npm install <pkg>` afterwards to install a package and save it as a dependency in the package.json file. Press ^C at any time to quit. package name: (demo04_npm) version: (1.0.0) description: entry point: (index.js) test command: git repository: keywords: author: license: (ISC) About to write to C:\Users\Admin\Desktop\dfxt\dfxt_day02\web\NodeJSDemo\demo04_npm\package.json: { "name": "demo04_npm", # 项目名称 "version": "1.0.0", # 项目版本号 "description": "", # 项目描述 "main": "index.js", # 入口文件 "scripts": { # 脚本 "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", # 作者 "license": "ISC" # 认证信息 } Is this OK? (yes) yes |
npm init 命令的作用是将文件夹初始化为一个“包”,创建 package.json 文件,执行完npm init后会生成package.json文件,这个是包的配置文件,相当于maven的pom.xml,我们之后也可以根据需要进行修改。
1)安装镜像
install命令用于安装某个模块,如果我们想安装jquery模块,输出命令如下:
1 2 |
# 下载最新版本的jquery npm install jquery |
在该目录下已经出现了一个node_modules文件夹和package-lock.json文件。
我们再打开package.json文件,发现刚才下载的jquery已经添加到依赖列表中了,依赖包会被添加到dependencies节点下,类似maven中的<dependencies>标签。
安装时想指定特定的版本:
1 |
npm install jquery@3.2.1 |
查看package.json的依赖:
1 2 3 |
"dependencies": { "jquery": "^3.2.1" } |
2)版本号说明
npm安装依赖说明:
场景 | 实际安装版本 |
---|---|
npm install vue | 安装 latest 标签对应的版本(如 Vue 3.4.21) |
npm install vue@next | 安装 next 标签对应的版本(如 Vue 3.4.21-beta) |
npm install vue@3.2.0 | 安装精确指定版本(3.2.0) |
npm ci | 严格按 package-lock.json 安装,确保环境一致性 |
3)全局安装
在 npm 中,-g 是 --global 的缩写,表示全局安装。它的作用是将一个包(package)安装到系统的全局环境中,而不是当前项目的本地目录。全局安装后的包可以在系统的任何目录下通过命令行直接使用。
全局安装适用于需要跨项目使用的命令行工具或全局工具。例如:vue-cli(Vue 脚手架)、create-react-app(React 脚手架)、nodemon(自动重启 Node 服务)等。
全局安装的路径:
C:\Users\<用户名>\AppData\Roaming\npm\node_modules
/usr/local/lib/node_modules
安装与卸载全局包:
1 2 |
npm install -g @vue/cli # 全局安装 Vue CLI(跨项目使用) npm uninstall -g @vue/cli # 卸载全局的 Vue CLI |
4)运行依赖和开发依赖
我们使用npm install <packageName>就能在线下载依赖到本地的node_modules目录,但我们项目打包时通常不会打包项目的node_modules以减轻项目大小。当项目发送给了团队的其他成员时只有源代码而没有项目所需的依赖,此时项目是无法运行的。
因此我们安装某个依赖时,除了下载依赖项到本地的node_modules目录外,还应该记录当前项目的依赖项配置,这样就算其他人获得到了项目源代码也可以按照依赖项配置来下载当前项目所需依赖。
在安装(npm install xxx)某个依赖项时,可以通过配置--save或--save-dev来将该依赖项记录下来:
Tips:从npm 5.0.0版本开始,默认行为改变了。现在当运行npm install xxx时,npm会自动将包添加到dependencies中,相当于之前需要–save的效果。
如下:
1 2 3 4 5 6 7 8 9 10 |
{ // jquery是开发依赖 "devDependencies": { "jquery": "^3.7.1" }, // bootstrap是生产依赖 "dependencies": { "bootstrap": "^5.3.5" } } |
项目运行时必须依赖的包(无论是本地开发、生产环境还是其他环境),例如一些框架或常用库,如:JQuery、Bootstrap、Vue、axios等依赖,如果缺少这些依赖,代码将无法运行,这些依赖就应该是dependencies;
一些仅在开发阶段需要的依赖,生产环境不需要。例如一些构建、转码、测试工具等,如webpack、babel、eslint、jest等,这些依赖投入到生产环境中就再也不需要了,这些依赖就应该是devDependencies;
1.6.5 package和package-lock文件 1)package文件:
package.json定义了这个项目所需要的各种模块,以及项目的配置信息,包括名称、版本、许可证、依赖模块等元数据。
当执行 npm install 的时候,node 会先从 package.json 文件中读取所有 dependencies 信息,然后根据 dependencies 中的信息与 node_modules 中的模块进行对比,没有的直接下载,已有的检查更新。另外,package.json 文件只记录你通过 npm install 方式安装的模块信息,而这些模块所依赖的其他子模块的信息不会记录。
2)package-lock文件:
package.json文件中保存着项目的依赖以及这些依赖的版本信息,但是这些依赖的版本并非是一个固定的,而是可以随着时间的流逝(例如该依赖发布了新版本)自动更新的。因此,同一个package.json在不同时间点执行npm install可能会导致项目实际使用的依赖版本不同。
如项目中JQuery依赖为ˆ3.2.1,当前该依赖最新发布版本为3.5.1,执行npm install命令后将3.5.1版本的JQuery下载到了项目中。四个月后JQuery官方对其进行更新,当前最新版本为3.7.1,此时从新执行该项目的``npm install`将会安装3.7.1版本的JQuery。
可以看到,同一个项目,不同时间点来执行安装命令会导致项目的依赖版本不一样。package-lock.json文件正是来解决这个问题的。
package-lock.json 文件会保存 node_modules 中所有包的信息,包括精确版本 version 和下载地址 resolved 以及依赖关系 dependencies 等,用以记录当前状态下实际安装的各个模块的具体来源和版本号。这样 npm install 时速度就会提升。
当项目中已有package-lock.json 文件,在安装项目依赖时,将以该文件为主进行解析安装指定版本依赖包,而不是使用 package.json 来解析和安装模块。因为 package.json 指定的版本不够具体,而package-lock 为每个模块及其每个依赖项指定了版本,位置和完整性哈希,所以它每次的安装都是相同的。
package-lock.json 文件主要作用有以下两点:
1)当删除 node_module 目录时,想通过 npm install 恢复所有包时,提升下载速度。
2)锁定版本号,防止自动升级新版本。
项目中存在了package-lock.json当下载依赖时会以该文件中锁定的版本来下载,但有时我们也希望更新一下项目依赖,此时可以执行npm update来更新项目的依赖版本,并且更新package-lock.json锁定的版本。
一般来说前端工程完毕后是不会将node_modules文件夹打包到项目中的(精简项目),当项目发布到互联网时,用户需要自行执行npm install来根据package.json或package-lock.json文件来下载依赖。如果项目中没有package-lock.json可以使用如下命令来构建一个package-lock.json:
1 |
npm install --package-lock-only |