谈谈对Node的理解
Node.js 在浏览器外运行V8 JavaScript引擎,单线程 非阻塞I/O 事件驱动,适应于数据高并发,适合多请求,但不适合高运算,有权限读取操作系统级别的API,无法直接渲染静态页面,提供静态服务,没有根目录的概念,必须通过路由程序指定文件才能渲染文件,比其他服务端性能更好,速度更快,npm 仓库,常用框架:Express,koa,Socket.io,AdonisJs,NestJS
什么是gulp?作用?机制是什么?常用命令有哪些?
gulp是基于node的自动化构建工具
作用:
1 自动压缩JS文件
2 自动压缩CSS文件
3 自动合并文件
4 自动编译sass
5 自动压缩图片
6 自动刷新浏览器
机制:
Unix操作系统的管道(pipe)思想 前一级输出 后一级输入
常用命令:
.src 输出(Emits)符合所提供的匹配模式(glob)或者匹配模式的数组(array of globs)的文件。 将返回一个 Vinyl files 的 stream 它可以被 piped 到别的插件中。
.watch 监视文件,并且可以在文件发生改动时候做一些事情。它总会返回一个 EventEmitter 来发射(emit) change 事件。
.dest 能被 pipe 进来,并且将会写文件。并且重新输出(emits)所有数据,因此你可以将它 pipe 到多个文件夹。如果某文件夹不存在,将会自动创建它。
.pipe 传入方法的是一个function,这个function作用无非是接受上一个流(stream)的结果,并返回一个处理后流的结果(返回值应该是一个stream对象)。
.task 定义一个使用 Orchestrator 实现的任务(task)
如何判断当前脚本运行在浏览器还是node环境中?
this === window ? 'browser' : 'node',通过判断Global对象是否为window,如果不为window,当前脚本没有运行在浏览器中
node.js有哪些常用模块?
util是node 里面一个工具模块,node里面几乎所有的模块都会用到这个模块
功能:
1:实现继承这是主要功能
2:实现对象的完整输出
3:实现判断数据类型
path模块
功能:格式规范化路径
fs模块
功能:
1:操作文件
2:操作目录
http模块:用于搭建HTTP服务端和客户端
url模块:用户解析和处理URL字符串
url.parse(将url字符串解析并返回一个url的对象)
url.format(将url对象编程一个url字符串并返回)
url.resolve(将url中的参数用/进行拼接)
zlib模块:提供了用Gzip和Deflate/Inflate实现的压缩功能
socket.io: 实现客服端与服务端之间的实时通信方式
uglify-js: 用来压缩合并js文件
child_process:新建子进程。
querystring:解析URL中的查询字符串。
crypto:提供加密和解密功能。
Express框架的核心特性是什么
1.可以设置中间件来响应http请求
2.定义了路由表用于执行不同的HTTP请求动作
3.可以通过向模板传递参数来动态渲染html页面
对Node的思想一切皆异步的理解
node本身就是非阻塞I/O,与其他后端编程思想不同,虽然php, python, java中也有异步方法,但是编程人员的思想是同步的,node的思想目的是可以让开发者轻松编写高性能的web服务端,而不会通过同步思想api阻塞了服务器从而影响性能。而且node.js大部分api都是异步的,只有小量同步api,这与其他大部分语言刚好相反。
node如何实现异步非阻塞(I/O)
在node中,I/O(输入输出)是异步非堵塞的关键,I/O操作通常比较耗时但不会独占CPU,典型的I/O比如文件读写,远程数据库读写,网络请求等,如果用同步API来进行I/O操作,在返回结果之前就只能等待,此时阻塞代码会霸占cpu,导致本进程所有代码都等待,而node.js里面的I/O API都是不会霸占CPU的(原因:node中的核心库libuv会将建立的所有I/O操作内容绑定到单个线程上。只要每个事件循环在不同的线程中,就可以运行多个事件循环,libuv为Node.js提供了跨平台、线程池、事件池、异步I/O等能力),所以是非阻塞的。拿JS中的setTimeout来打比方,当用户使用setTimeout时,JS会开辟出一个异步线程池,与主线程分开执行,结果就是之前的代码继续执行,setTimeout的代码延时执行,等成功后再调用主线程的方法
node中的exports如何实现的,它和module.exports有什么关系
exports实现:exports = module.exports = {};就好像是var a = { } var b = a,看上去没有太大区别,但使用起来却又不同
module是一个对象,当我们在控制台输入node并执行,在node中执行module或者执行js文件打印module时会发现以下log
Module {
id: '',
path: '.',
exports: {},
parent: undefined,
filename: null,
loaded: false,
children: [],
paths: [
...
]
}
不难发现,module是Module的实例,exports是其中一个属性,也就是说当你在node中执行一个js文件或者使用require引入模块时,nodejs都会新建一个var module = new Module(),并执行exports = module.exports,这也就是为什么直接打印exports和exports时,控制台不会报错,如果在node中执行以下代码,就能清楚的看出这二者的引用关系了
console.log(module.exports) // {}
console.log(exports) // {}
module.exports.name = '张三'
exports.age = 22
console.log(module.exports) // { name: '张三', age: 22 }
console.log(exports) // { name: '张三', age: 22 }
谈谈Node.js加载模块机制
node.js中模块有两种类型:核心模块和文件模块
核心模块直接使用名称获取,文件模块只能按照路径加载(可以省略默认的.js拓展名,不是js文件的话需要显示声明书写)
模块加载规则:
对Node的优点和缺点提出了自己的看法
优点:因为Node是基于事件驱动和无阻塞的,所以非常适合处理并发请求, 因此构建在Node上的代理服务器相比其他技术实现(如Ruby)的服务器表现要好得多。 此外,与Node代理服务器交互的客户端代码是由javascript语言编写的, 因此客户端和服务器端都用同一种语言编写,这是非常美妙的事情。
缺点:Node是一个相对新的开源项目,所以不太稳定,它总是一直在变, 而且缺少足够多的第三方库支持(第三方库现在已经很丰富了,所以这个缺点可以说不存在了)。看起来,就像是Ruby/Rails当年的样子。
Node.js的适用场景
原生Node如何解决跨域
const http = require('http');
http.createServer((req, res) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader("Access-Control-Allow-Headers", "X-Requested-With");
res.setHeader("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
}).listen(8080);
反向代理是什么,如何实现
反向代理是指代理服务器来接受客户端的网络访问连接请求,然后服务器将请求有策略的转发给网络中实际工作的业务服务器,并将从业务服务器处理的结果,返回给网络上发起连接请求的客户端
实现过程(这里的目标服务器是用getman产生的假数据):
前端部分:
Document
//服务端
const http = require('http');
const https = require('https')
const reqOption = { // getman产生的虚拟数据的请求地址
protocol: 'https:',
host: 'getman.cn',
path: '/mock/shopList',
method: 'POST',
headers: {
"content-type": "application/json",
}
}
let server = http.createServer((req, res) => {
// 写请求头,解决跨域
res.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:5500'); // 若允许所有域名和ip,则设置成*
res.setHeader("Access-Control-Allow-Headers", "X-Requested-With");
res.setHeader("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
let _data = ''
req.on('data', data => _data += data)
req.on('end', () => {
proxyApi(_data).then((_res) => { // 服务端收到前端请求后,请求目标服务器,将结果返回至前端
res.write(_res)
res.end()
})
})
})
function proxyApi(_data) {
return new Promise((resolve, reject) => {
let req = https.request(reqOption, (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
resolve(data)
});
})
req.write(_data)
req.end();
})
}
server.listen(1024, () => console.log("1024服务开启,开始侦听"));
Node事件循环的流程是什么,在事件循环中,如何判断是否有事件需要处理呢
事件循环的流程:在进程启动时,node会生成一个循环(类似于while(true)),每执行一次循环被称为一次Tick,每次的循环体Tick的过程会对事件进行判断,若发现存在事件,则执行相关操作,并进入下一个Tick,如果不再有事件,则退出进程
判断Tick是否有事件:node中的Tick通过观察者判断是否有需要处理的事件,主要来源于网络请求的网络I/O观察者,和文件操作的文件I/O观察者,事件循环从观察者中取出事件并处理
webSocket相对http的优势
简述明文、密文、密码、密钥、对称加密、非对称加密、摘要、数字签名、数字证书的概念
什么是中间件,好处是什么
中间件是一类连接软件组件和应用的计算机软件,它包括一组服务。以便于运行在一台或多台机器上的多个软件通过网络进行交互。使用node作为中间件更好提升了性能。
好处:
node中的Connect模块是什么,Koa与Express的中间件有什么区别
Connect是一个node中间件(middleware)框架,每个中间件在http处理过程中通过改写request或(和)response的数据、状态,实现了特定的功能
Koa与Express中间件的区别:
Express主要基于Connect中间件框架,中间件一个接一个的顺序执行,通常会将 response 响应写在最后一个中间件中
而koa主要基于co中间件框架,它的中间件是通过 async await
实现的,中间件执行顺序是“洋葱圈”模型。执行效果类似于Promise.all