目录
⭐node你需要掌握:
- 包管理:npm、 yarn、 npx;
- 常用包:文件读写fs、 路径查找path、 网络http。
前言
什么是Node.js?
- Node.js 不是一门语言,也不是 JavaScript 的框架,也不是像Nginx一样的Web服务器 ,而是 JavaScript 在服务器端的运行环境(平台)。
- Node.js 使用了一个事件驱动、非阻塞式 I/O的模型,使其轻量又高效。Node.js 的包管理工具 npm 是全球最大的开源库生态系统。
- Node.js 内部采用 Google Chrome 的 V8 引擎,作为 JavaScript 语言解释器;同时结合自行开发的 libuv 库,扩展了 JS 在后端的能力(比如 I/O 操作、文件读写、数据库操作等)。使得 JS 既可以在前端进行 DOM 操作(浏览器前端),又可以在后端调用操作系统资源,是目前最简单的全栈式语言。
为什么要学Node.js?
- 了解前后端交互流程;
- Node.js 使用 JavaScript 语言开发服务器端应用,便于前端同学上手;
- 实现了前后端的语法统一,有利于和前端代码整合,甚至共用部分代码;
- Node.js 性能高、生态系统活跃,提供了大量的开源库。
模块化
① 简介
在【ES6】学Vue前必须掌握的内容(下) 这篇文章中解释了模块化的基本概念,不过这里面说明的import & export是 ES6规范 的。
模块化规范:对代码进行模块化的拆分与组合时,需要遵守的那些规则。
模块化规范还有:
- 服务器端规范 :CommonJS规范(是 Node.js 使用的模块化规范)
- 浏览器端规范:AMD规范和CMD规范
// PS:面试时,经常会问AMD 和 CMD 的区别。
- AMD规范:是RequireJS在推广过程中对模块化定义的规范化产出。
- 异步加载模块;
- 依赖前置、提前执行:require([`foo`,`bar`],function(foo,bar){}); //也就是说把所有的包都 require 成功,再继续执行代码。
- define 定义模块:define([`require`,`foo`],function(){return});
- CMD规范:是SeaJS在推广过程中对模块化定义的规范化产出。淘宝团队开发。
- 同步加载模块;
- 依赖就近,延迟执行:require(./a) 直接引入。或者Require.async 异步引入。 //依赖就近:执行到这一部分的时候,再去加载对应的文件。
- define 定义模块, export 导出:define(function(require, export, module){});
Node.js中根据模块的来源,将模块分成了3类:
- 内置模块:由Node.js官方提供,如fs、path、http等;⭐
- 自定义模块:用户创建的每个js文件;
- 第三方模块:非官方提供也不是用户创建,使用前需要下载。
② 模块的暴露与引入
暴露模块:exports 和 module.exports
//方式一:exports ,相当于是给exports对象添加属性
//类似于ES6中的export,都是用来导出一个指定名字的对象
exports.xxx = xxxx;
//方式二:module.exports ,用来导出一个默认对象,没有指定对象名
module.exports = xxxx;//导出整个exports对象
module.exports.xxx = xxxx;//给exports对象添加属性
exports 和 module.exports 的区别:
- exports只能单个设置属性;
- module.exports既能设置单个也能整个赋值。
引入模块:require
require函数用来在一个模块中引入另外一个模块。传入模块名,返回模块导出对象。
const mod = require('xxx');
//内置模块和第三方模块,写模块名
//自定义模块,写文件路径
一个模块中的 JS 代码仅在模块第一次被使用时执行一次,并且在使用的过程中进行初始化,然后会被缓存起来,便于后续继续使用。
//暴露模块
let num=1;
function add(){
num++;
return num;
}
exports.add=add;
//引入自定义模块
//文件可以省略.js后缀
let m1=require('../xx/xxx');
console.log(m1.add()); //2
let m2=require('../xx/xxx');
console.log(m1.add()); //3
包管理
① npm
相当于手机里的应用商店,可以下载很多安装包
- npm install <package-name> 安装单个软件包 (npm i <>)
- npm update <package-name> 更新软件包
- npm run <task-name> 运行任务
- npm uninstall <package-name> 卸载npm软件包
- -g 标志可以执行全局安装
- -S 就是--save的简写,会将包的名称以及版本号放在package.json的dependencies里
- -D 就是--save-dev,这样安装的包的名称以及版本号就会存在package.json的devDependencies这个里面
npm包的管理都是通过项目根目录的package.json文件实现:
⭐package.json 包管理配置文件:在项目根目录中必须存在,用来记录与项目有关的一些配置信息,如:项目的名称版本号等、项目用到了哪些包、哪些包只在开发期间用到、哪些包在开发和部署时都需要。
在开发阶段和项目上线后都需要包(核心依赖包)记录到上面提到的dependencies节点;
只在开发期间用到包(开发依赖包)就记录到devDependencies节点。
② yarn
yarn是由Facebook、Google、Exponent 和 Tilde 联合推出了一个新的 JS 包管理工具,yarn是为了弥补 npm 的一些缺陷而出现的。
(后续再补充...)
③ npx
npm
侧重于安装或者卸载某个模块的。重在安装,并不具备执行某个模块的功能。npx
侧重于执行命令的,执行某个模块命令。虽然会自动安装模块,但是重在执行某个命令。
常用包
常用的三个包都是Node内置模块:文件处理模块fs、路径查找模块path、网络http
① 文件处理模块 fs
在使用文件模块之前,记得先导入:
const fs = require('fs');
// fs 的英文全称是 File System。
异步读取文件 fs.readFile() ⭐
fs.readFile( file_path [, 编码格式] , callback( err, data ))
//编码格式不设置的话则以buffer的格式输出
const fs = require('fs');
fs.readFile('./hello.txt','utf-8',(err,data)=>{
if(err){
console.log(err);
}
else{
console.log(data); //hello
}
})
如果需要嵌套读取多个文件,可以用 promise 或者 async ... await 进行封装。
const fs=require('fs');
function fsRead(path){
return new Promise((resolve,reject)=>{
fs.readFile(path,'utf-8',(err,data)=>{
if(err){
reject(err);
}else{
resolve(data);
}
})
})
}
// 下面是两种方式,async ... await 封装 fs.readFile()这个写法更为简洁,推荐。
let p=fsRead('./test1.txt');
p.then((data1)=>{
console.log(data1); //test1
return fsRead('./test2.txt');
}).then((data2)=>{
console.log(data2); //test2
return fsRead('./test3.txt');
}).then((data3)=>{
console.log(data3); //test3
})
async function p(){
let data1=await fsRead('./test1.txt');
console.log(data1); //test1
let data2=await fsRead('./test2.txt');
console.log(data2); //test2
let data3=await fsRead('./test3.txt');
console.log(data3); //test3
}
p();
同步读取文件fs.readFileSync()
fs.readFileSync(file_path [,编码格式] )
const fs=require('fs');
try{
let data=fs.readFileSync('test.txt','utf-8');
console.log(data);
}catch(e){
throw e;
}
fs模块对文件的几乎所有操作都有同步和异步两种形式。例如:readFile() 和 readFileSync()。
区别:
同步调用会阻塞代码的执行,异步则不会。
异步调用会将 读取任务 下达到任务队列,直到任务执行完成才会回调。
异常处理方面:同步必须使用 try catch 方式,异步可以通过回调函数的第一个参数。
写入文件 fs.write()
fs.write( file_path, data [, 编码格式] , callback(err) )
const fs=require('fs');
fs.writeFile('./test1.txt', 'hello world', 'utf-8', (err) => {
if(err){
console.log(err);
}
else{
console.log('写入成功');
}
})
② 路径模块 path
引入内置模块:
const path = require('path');
path.extname( mypath ) 获取文件/路径的扩展名
const path=require('path');
console.log(path.extname('test2.txt')); //.txt
console.log(path.extname('www.baidu.com'); //.com
- mypath 这个参数要求是字符串。如果不是字符串,则抛出 TypeError。
path.basename(),从一个文件路径中获取文件名
const path=require('path');
console.log('a/b/c.js'); // c.js
path.join() 将多个路径进行拼接
const path = require('path');
const result1 = path.join(__dirname, './app.js');
console.log(result1); // 输出 当前文件所在目录\app.js
const result2 = path.join('/foo1', '/foo2/foo3', '../', './foo4', 'foo5');
console.log(result2); // 输出 foo1\foo2\foo4\foo5
如果是我们手动拼接路径,容易出错。这个时候,可以利用 path.join() 方法将路径进行拼接。它使用平台特定的分隔符作为定界符将所有给定的 path 片段连接在一起,然后规范化生成的路径。
- _dirname:常量, 表示当前执行文件所在的完整目录
- _filename: 常量,表示当前执行文件的完整目录+文件名
③ 网络模块 http
用来创建web服务器。通过http模块提供的http.creatServe()方法能方便的把一台普通的电脑,变成一台Web服务器,从而对外提供Web资源服务。
创建最基本的web服务器步骤:
- 导入http模块。const http=require('http')
- 创建web服务器实例。const serve=http.createServer()
- 为服务器绑定request事件。server.on('request',(request,respone)=>{})
- 启动服务器 。serve.listen(端口号,()=>{})
const http=require('http');
const sreve=http.createServer();
sreve.on('request',(req,res)=>{
console.log('有人访问...');
//req.url获取请求的url地址,req.method请求方式
const str=`地址是${req.url} ,方式是${req.method}`;
//防止乱码
res.setHeader('Content-Type','text/html;charset=UTF-8');
//res.end()将内容响应给客户端
res.end(str)
})
sreve.listen(8010,()=>{
console.log('http://ip地址:8010');
})
这样,在同一片局域网内,不同设备都可以访问