NodeJs(前端面试题整合)

1.谈谈对 Node 的理解

Node.js 在浏览器外运行 V8 JavaScript 引擎,单线程 非阻塞 I/O 事件驱动,适应于数据高并发,适合多请求,但不适合高运算,有权限读取操作系统级别的 API,无法直接渲染静态页面,提供静态服务,没有根目录的概念,必须通过路由程序指定文件才能渲染文件,比其他服务端性能更好,速度更快,npm 仓库,常用框架:Express,koa,Socket.io,AdonisJs,NestJS

2.什么是 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)

3.如何判断当前脚本运行在浏览器还是 node 环境中?

this === window ? 'browser' : 'node',通过判断 Global 对象是否为 window,如果不为 window,当前脚本没有运行在浏览器中

4.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:提供加密和解密功能。

5.Express 框架的核心特性是什么

  1. 可以设置中间件来响应 http 请求

  2. 定义了路由表用于执行不同的 HTTP 请求动作

  3. 可以通过向模板传递参数来动态渲染 html 页面

6.对 Node 的思想一切皆异步的理解

node 本身就是非阻塞 I/O,与其他后端编程思想不同,虽然 php, python, java 中也有异步方法,但是编程人员的思想是同步的,node 的思想目的是可以让开发者轻松编写高性能的 web 服务端,而不会通过同步思想 api 阻塞了服务器从而影响性能。而且 node.js 大部分 api 都是异步的,只有小量同步 api,这与其他大部分语言刚好相反。

7.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 的代码延时执行,等成功后再调用主线程的方法

8.node 中的 exports 如何实现的,它和 module.exports 有什么关系

exports 实现:exports = module.exports = {}; 就好像是 var a = { } var b = a,看上去没有太大区别,但使用起来却又不同

module 是一个对象,当我们在控制台输入 node 并执行,在 node 中执行 module 或者执行 js 文件打印 module 时会发现以下 log

Module {
  id: '<repl>',
  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 }

9.谈谈 Node.js 加载模块机制

node.js 中模块有两种类型:核心模块和文件模块

核心模块直接使用名称获取,文件模块只能按照路径加载(可以省略默认的.js 拓展名,不是 js 文件的话需要显示声明书写)

模块加载规则:

  • 核心模块优先级最高,直接使用名字加载,在有命名冲突的时候首先加载核心模块
  • 可通过绝对路径和相对路径查找
  • 查找 node_modules 目录,我们知道在调用 npm install <name> 命令的时候会在当前目录下创建 node_module 目录 (如果不存在) 安装模块,当 require 遇到一个既不是核心模块,又不是以路径形式表示的模块名称时,会试图 在当前目录下的 node_modules 目录中来查找是不是有这样一个模块。如果没有找到,则会 在当前目录的上一层中的 node_modules 目录中继续查找,反复执行这一过程,直到遇到根 目录为止

10.对 Node 的优点和缺点提出了自己的看法

优点:因为 Node 是基于事件驱动和无阻塞的,所以非常适合处理并发请求, 因此构建在 Node 上的代理服务器相比其他技术实现(如 Ruby)的服务器表现要好得多。 此外,与 Node 代理服务器交互的客户端代码是由 javascript 语言编写的, 因此客户端和服务器端都用同一种语言编写,这是非常美妙的事情。

缺点:Node 是一个相对新的开源项目,所以不太稳定,它总是一直在变, 而且缺少足够多的第三方库支持(第三方库现在已经很丰富了,所以这个缺点可以说不存在了)。看起来,就像是 Ruby/Rails 当年的样子。

11.Node.js 的适用场景

  • 实时应用:如在线聊天,实时通知推送等等(如 socket.io
  • 分布式应用:通过高效的并行 I/O 使用已有的数据
  • 工具类应用:海量的工具,小到前端压缩部署(如 grunt),大到桌面图形界面应用程序
  • 游戏类应用:游戏领域对实时和并发有很高的要求(如网易的 pomelo 框架)
  • 利用稳定接口提升 Web 渲染能力
  • 前后端编程语言环境统一:前端开发人员可以非常快速地切入到服务器端的开发(如著名的纯 Javascript 全栈式 MEAN 架构)

12.原生 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);

13.反向代理是什么,如何实现

反向代理是指代理服务器来接受客户端的网络访问连接请求,然后服务器将请求有策略的转发给网络中实际工作的业务服务器,并将从业务服务器处理的结果,返回给网络上发起连接请求的客户端

实现过程(这里的目标服务器是用 getman 产生的假数据):

前端部分:
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>

</head>

<body>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <script>
        $.post('http://127.0.0.1:1024', {// 访问代理服务端,获取目标服务器的数据
            token: '1234'
        }, function (res) {
            console.log(JSON.parse(res))
        })
    </script>
</body>

</html>

//服务端
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服务开启,开始侦听"));

14.Node 事件循环的流程是什么,在事件循环中,如何判断是否有事件需要处理呢

事件循环的流程:在进程启动时,node 会生成一个循环(类似于 while(true)),每执行一次循环被称为一次 Tick,每次的循环体 Tick 的过程会对事件进行判断,若发现存在事件,则执行相关操作,并进入下一个 Tick,如果不再有事件,则退出进程

判断 Tick 是否有事件:node 中的 Tick 通过观察者判断是否有需要处理的事件,主要来源于网络请求的网络 I/O 观察者,和文件操作的文件 I/O 观察者,事件循环从观察者中取出事件并处理

15.webSocket 相对 http 的优势

  • 客户端与服务器只需要一个 TCP 连接,比 http 长轮询使用更少的连接
  • webSocket 服务端可以推送数据到客户端
  • 更轻量的协议头,减少数据传输量

简述明文、密文、密码、密钥、对称加密、非对称加密、摘要、数字签名、数字证书的概念

  • 明文(plaintext)是加密之前的原始数据
  • 密文是通过密码(cipher)运算后得到的结果成为密文(ciphertext)
  • 密码学中的密码(cipher)和我们日常生活中所说的密码不太一样,计算机术语 ' 密码 cipher ' 是一种用于加密或者解密的算法,而我们日常所使用的 密码 (password) 是一种口令,它是用于认证用途的一组文本字符串,这里我们要讨论的是前者:cipher。
  • 密钥 (key) 是一种参数,它是在明文转换为密文或将密文转换为明文的算法中输入的参数。密钥分为对称密钥与非对称密钥,分别应用在对称加密和非对称加密上。
  • 对称密钥(Symmetric-key algorithm)又叫做私钥加密,即信息的发送方和接收方使用同一个密钥去加密和解密数据。对称加密的特点是算法公开、加密和解密速度快,适合于对大数据量进行加密,常见的对称加密算法有 DES、3DES、TDEA、Blowfish、RC5 和 IDEA。
  • 非对称密钥(public-key cryptography)也叫做公钥加密。非对称加密与对称加密相比,其安全性更好。对称加密的通信双方使用相同的密钥,如果一方的密钥遭泄露,那么整个通信就会被破解。而非对称加密使用一对密钥,即公钥和私钥,且二者成对出现。私钥被自己保存,不能对外泄露。公钥指的是公共的密钥,任何人都可以获得该密钥。用公钥或私钥中的任何一个进行加密,用另一个进行解密。
  • 摘要算法又称哈希 / 散列算法。它通过一个函数,把任意长度的数据转换为一个长度固定的数据串(通常用 16 进制的字符串表示)。算法不可逆。
  • 数据在浏览器和服务器之间传输时,有可能在传输过程中被冒充的盗贼把内容替换了,那么如何保证数据是真实服务器发送的而不被调包呢,同时如何保证传输的数据没有被人篡改呢,要解决这两个问题就必须用到数字签名,数字签名就如同日常生活的中的签名一样,一旦在合同书上落下了你的大名,从法律意义上就确定是你本人签的字儿,这是任何人都没法仿造的,因为这是你专有的手迹,任何人是造不出来的。那么在计算机中的数字签名怎么回事呢?数字签名就是用于验证传输的内容是不是真实服务器发送的数据,发送的数据有没有被篡改过,它就干这两件事,是非对称加密的一种应用场景。不过他是反过来用私钥来加密,通过与之配对的公钥来解密。
  • 数字证书是指在互联网通讯中标志通讯各方身份信息的一个数字认证,人们可以在网上用它来识别对方的身份。因此数字证书又称为数字标识。数字证书对网络用户在计算机网络交流中的信息和数据等以加密或解密的形式保证了信息和数据的完整性和安全性。

16.什么是中间件,好处是什么

中间件是一类连接软件组件和应用的计算机软件,它包括一组服务。以便于运行在一台或多台机器上的多个软件通过网络进行交互。使用 node 作为中间件更好提升了性能。

好处:

  • 代理,处理前端产生的访问接口跨域,通过 node 反向代理,访问目标服务器
  • 缓存,用户触发数据更新时,使用 node 作为暂时缓存,节省后端资源
  • 限流,针对接口和路由做出响应路由
  • 监控,高并发请求特点
  • 鉴权,对页面路由权限做出判断
  • 渲染,使用 node 对前端页面进行预渲染
  • 等等...

17.node 中的 Connect 模块是什么,Koa 与 Express 的中间件有什么区别

Connect 是一个 node 中间件(middleware)框架,每个中间件在 http 处理过程中通过改写 request 或(和)response 的数据、状态,实现了特定的功能

18.Koa 与 Express 中间件的区别:

Express 主要基于 Connect 中间件框架,中间件一个接一个的顺序执行,通常会将 response 响应写在最后一个中间件中

而 koa 主要基于 co 中间件框架,它的中间件是通过 async await 实现的,中间件执行顺序是 "洋葱圈" 模型。执行效果类似于 Promise.all

仅供参考!!

相关推荐
狸克先生10 分钟前
如何用AI写小说(二):Gradio 超简单的网页前端交互
前端·人工智能·chatgpt·交互
sinat_3842410912 分钟前
在有网络连接的机器上打包 electron 及其依赖项,在没有网络连接的机器上安装这些离线包
javascript·arcgis·electron
baiduopenmap24 分钟前
百度世界2024精选公开课:基于地图智能体的导航出行AI应用创新实践
前端·人工智能·百度地图
loooseFish32 分钟前
小程序webview我爱死你了 小程序webview和H5通讯
前端
小牛itbull36 分钟前
ReactPress vs VuePress vs WordPress
开发语言·javascript·reactpress
请叫我欧皇i44 分钟前
html本地离线引入vant和vue2(详细步骤)
开发语言·前端·javascript
533_1 小时前
[vue] 深拷贝 lodash cloneDeep
前端·javascript·vue.js
guokanglun1 小时前
空间数据存储格式GeoJSON
前端
GIS瞧葩菜1 小时前
局部修改3dtiles子模型的位置。
开发语言·javascript·ecmascript
zhang-zan1 小时前
nodejs操作selenium-webdriver
前端·javascript·selenium