Nodejs教程-Node.js 面试问题
下面是一些常见的 Node.js 面试问题 和答案列表:
1) 什么是 Node.js?
Node.js 是一种用于构建可扩展程序的服务器端脚本语言。它是一个基于 Google Chrome 的 JavaScript 引擎构建的 Web 应用程序框架。它在 Mac OS、Windows 和 Linux 上的 Node.js 运行时中运行,而无需进行任何更改。该运行时使您能够在浏览器外的任何计算机上执行 JavaScript 代码。
2) Node.js 是否免费使用?
是的,Node.js 是在 MIT 许可下发布的,免费使用。
3) Node 是否是单线程应用程序?
是的,Node 是一个单线程应用程序,具有事件循环。
4) Node.js 的目的是什么?
Node.js 的主要目的有:
- 实时 Web 应用程序
- 网络应用程序
- 分布式系统
- 通用应用程序
5) Node.js 的优势有哪些?
以下是 Node.js 的主要优势:
- Node.js 是异步和事件驱动的。所有 Node.js 库的 API 都是非阻塞的,其服务器在调用 API 后不会等待 API 返回数据。它在调用后转移到下一个 API,并且 Node.js 事件通知机制会从先前的 API 调用中响应服务器。
- Node.js 非常快,因为它构建在 Google Chrome 的 V8 JavaScript 引擎上。它的库在代码执行方面非常快。
- Node.js 是单线程的,但高度可扩展。
- Node.js 不提供缓冲功能。其应用程序从不缓冲任何数据。它以分块方式输出数据。
6) 解释 Node.js Web 应用程序架构是什么?
Web 应用程序分为四个层:
- 客户端层: 客户端层包含 Web 浏览器、移动浏览器或可以向 Web 服务器发出 HTTP 请求的应用程序。
- 服务器层: 服务器层包含 Web 服务器,它可以拦截客户端发出的请求并将响应传递给客户端。
- 业务层: 业务层包含应用程序服务器,Web 服务器使用它来执行所需的处理。此层通过数据库或某些外部程序与数据层进行交互。
- 数据层: 数据层包含数据库或任何数据源。
7) 什么是 I/O?
I/O 代表输入和输出。它用于访问应用程序外部的任何内容。I/O 用于描述任何传输数据的程序、操作或设备,该数据可以从一个媒体传输到另一个媒体。这个媒体可以是物理设备、网络或系统内的文件。
一旦应用程序启动,I/O 就会加载到计算机内存中以运行程序。
8) Node.js 中有多少种类型的 API 函数?
Node.js 中有两种类型的 API 函数:
- 异步、非阻塞函数
- 同步、阻塞函数
9) 什么是 JavaScript 中的一等函数?
当函数被像任何其他变量一样对待时,那么这些函数被称为一等函数。除了 JavaScript,许多其他编程语言,如 Scala、Haskell 等,都遵循这种模式。一等函数可以作为参数传递给另一个函数(回调函数),或者函数可以返回另一个函数(高阶函数)。一些常用的高阶函数示例包括 map()
和 filter()
。
10) JavaScript 和 Node.js 之间有什么区别?
JavaScript 和 Node.js 的区别
下表列出了 JavaScript 和 Node.js 之间的关键区别:
比较特点 | JavaScript | Node.js |
---|---|---|
类型 | JavaScript 是一种编程语言。更准确地说,它是一种用于在网站上编写脚本的脚本语言。 | Node.js 是 JavaScript 的解释器和运行时环境。 |
功能 | JavaScript 用于 Web 应用程序的任何客户端活动。 | Node.js 用于访问或执行任何操作系统的非阻塞操作。 |
运行引擎 | JavaScript 的运行引擎有 Spider monkey(Firefox)、JavaScript Core(Safari)、V8(Google Chrome)等。 | Node.js 的运行引擎是 V8(Google Chrome)。 |
浏览器兼容性 | JavaScript 只能在浏览器中运行。 | Node.js 代码可以在浏览器之外运行。 |
平台依赖性 | JavaScript 基本上用于客户端,并用于前端开发。 | Node.js 主要用于服务器端,并用于服务器端开发。 |
HTML 兼容性 | JavaScript 足够强大,可以添加 HTML 并与 DOM 交互。 | Node.js 不太兼容,无法添加 HTML 标签。 |
示例 | JavaScript 框架的一些示例包括 RamdaJS、TypedJS 等。 | Node.js 模块的一些示例包括 Lodash、express 等。我们必须从 npm 导入这些模块。 |
编写语言 | JavaScript 是 ECMA 脚本的升级版本,使用了 Chrome 的 V8 引擎,用 C++ 编写。 | Node.js 是用 C++ 编写的。 |
应用 | JavaScript 用于在浏览器中构建交互式网页和应用程序。 | Node.js 用于构建服务器端应用程序。 |
并行性 | JavaScript 是单线程的,不适合 CPU 密集型操作。 | Node.js 支持并行性,适用于高性能的分布式应用程序。 |
I/O 操作 | JavaScript 通常用于简单的浏览器 I/O 操作。 | Node.js 用于执行复杂的非阻塞 I/O 操作。 |
11) 解释 Node.js 的工作原理?
Node.js Web 服务器的工作流程通常如下所示的图表。让我们详细了解操作流程:
- 根据上图,客户端发送请求与 Web 服务器进行交互,这些请求可以是非阻塞或阻塞的,用于查询数据、删除数据或更新数据。
- Node.js 接收传入的请求并将其添加到事件队列。
- 在此步骤之后,请求通过事件循环逐个传递。它检查请求是否足够简单,不需要任何外部资源。
- 事件循环然后处理简单请求(非阻塞操作),如 I/O 轮询,并将响应返回给相应的客户端。
- 从线程池中分配一个线程给单个复杂请求。此线程负责通过访问外部资源(如计算、数据库、文件系统等)来完成特定的阻塞请求。
- 任务完成后,响应发送到事件循环,然后将响应发送回客户端。
12) 如何管理 Node.js 项目中的软件包?
我们可以通过使用几个软件包安装器及其相应的配置文件来管理 Node.js 项目中的软件包。大多数情况下使用 npm 或 yarn。npm 和 yarn 都提供几乎所有 JavaScript 库,具有控制环境特定配置的扩展功能。我们可以使用 package.json 和 package-lock.json 来维护项目中安装的库的版本。因此,在将应用程序移植到不同环境时不会出现问题。
13) 为什么 Node.js 是单线程的?
Node.js 是一个采用事件循环进行异步处理的单线程应用程序。在典型的 Web 负载下,使用单线程进行异步处理的最大优势是,相较于典型的基于线程的实现,可以实现更好的性能和可扩展性。
14) 什么是 Node.js 中的回调地狱?
回调地狱是一种现象,当 JavaScript 开发者试图依次执行多个异步操作时,会给开发者带来很多问题。当在处理结果之前必须完成某些外部活动时,函数被称为异步函数。之所以称之为异步,是因为在结果可用之前有不可预测的时间。这些函数需要一个回调函数来处理错误并处理结果。
示例:
getData(function(a){
getMoreData(a, function(b){
getMoreData(b, function(c){
getMoreData(c, function(d){
getMoreData(d, function(e){
// ...
});
});
});
});
});
15) Node.js 如何优于其他流行的框架?
根据以下标准,我们可以说 Node.js 优于其他流行的框架:
- Node.js 通过其非阻塞 I/O 和事件驱动模型使开发变得简单。这种简单性导致更短的响应时间和并发处理,而其他框架需要开发者使用线程管理。
- Node.js 运行在一个用 C++ 编写的 Chrome V8 引擎上,这极大地提高了性能,并且在不断改进中。
- 使用 Node.js,我们可以在前端和后端开发中都使用 JavaScript,这将更加快速。
- Node.js 提供了丰富的库,使我们不需要重新发明轮子。
16) Node.js 最常用于哪些类型的应用程序?
Node.js 最常用于以下类型的应用程序:
- 物联网
- 实时协作工具
- 实时聊天
- 复杂的单页应用程序(SPAs)
- 流媒体应用程序
- 微服务架构等。
17) Node.js 中常用的定时特性有哪些?
以下是 Node.js 中常用的定时特性列表:
- setTimeout/clearTimeout: 用于在代码执行中实现延迟。
- setInterval/clearInterval: 用于在应用程序中多次运行代码块。
- setImmediate/clearImmediate: 用于在事件循环周期结束时设置代码的执行。
- nextTick: 此定时特性将代码的执行设置为在下一个事件循环周期的开始时。
18) Node.js 中的 fork 是什么意思?
一般来说,fork 用于生成子进程。在 Node.js 中,它用于创建一个新的 V8 引擎实例,以运行多个工作进程来执行代码。
19) 在 Node.js 中,我们可以使用哪个工具来确保一致的代码风格?
ESLint 工具是我们可以与任何集成开发环境(IDE)一起使用的最佳工具之一,以确保一致的代码风格。它还有助于维护代码库。
20) 前端开发和后端开发之间的主要区别是什么?
下表列出了前端开发和后端开发之间的主要区别:
前端开发 | 后端开发 |
---|---|
应用程序的前端开发涉及应用程序的客户端部分。 | 应用程序的后端开发涉及应用程序的服务器端部分。 |
正如名称所示,前端开发是 web 应用程序的用户可以看到和交互的部分。 | 正如名称所示,后端开发包括在幕后发生的一切,用户无法看到和交互。 |
前端开发包括与 web 应用程序的视觉方面相关的一切内容。 | 后端开发通常包括与数据库通信以为用户提供请求服务的 Web 服务器。 |
HTML、CSS、Bootstrap、jQuery、JavaScript、AngularJS 和 React.js 是必备的前端开发技术。 | Java、PHP、Python、C++、Node.js 等是后端开发所需的技术。 |
一些前端框架的示例包括 AngularJS、React.js、jQuery、Sass 等。 | 一些后端框架的示例包括 Express、Django、Rails、Laravel、Spring 等。 |
21) 举个例子,演示在 Node.js 中如何使用 async await?
以下是使用 async-await 模式的示例:
function wait(timeout) {
return new Promise((resolve) => {
setTimeout(() => {
resolve();
}, timeout);
});
}
async function requestWithRetry(url) {
const MAX_RETRIES = 10;
for (let i = 0; i <= MAX_RETRIES; i++) {
try {
return await request(url);
} catch (err) {
const timeout = Math.pow(2, i);
console.log('Waiting', timeout, 'ms');
await wait(timeout);
console.log('Retrying', err.message, i);
}
}
}
22) Node.js 中的模块是什么?有哪些不同的模块在 Node.js 中使用?
在 Node.js 应用程序中,模块类似于 JavaScript 库,并包含一组函数。要在 Node.js 应用程序中包含模块,必须使用 require() 函数,括号中包含模块的名称。
Node.js 有几个模块,用于为 Web 应用程序提供所需的基本功能。以下是其中一些模块的列表:
核心模块 | 描述 |
---|---|
HTTP | HTTP 模块包括创建 Node.js HTTP 服务器所需的类、方法和事件。 |
util | util 模块包含在应用程序中需要的实用函数,对开发人员非常有用。 |
url | url 模块用于包含 URL 解析方法。 |
fs | fs 模块包括处理文件 I/O 操作所需的事件、类和方法。 |
stream | stream 模块用于包含处理流式数据所需的方法。 |
query string | query string 模块用于包含处理查询字符串的方法。 |
zlib | zlib 模块用于包含压缩或解压在应用程序中使用的文件的方法。 |
23) 在 Node.js 中,什么是缓冲区(Buffers)?
通常情况下,缓冲区是由流使用的临时内存,用于保存数据,直到被消耗。缓冲区用于表示在 V8 JavaScript 引擎之外分配的固定大小的内存块。它无法调整大小。它类似于整数数组,每个整数代表一个字节的数据。它由 Node.js 的 Buffer 类实现。缓冲区还支持诸如 ASCII、utf-8 等的传统编码方式。
24) 什么是错误优先的回调(Error-First Callback)?
错误优先的回调用于传递错误和数据。如果出现问题,程序员必须检查第一个参数,因为它始终是一个错误参数。其他参数用于传递数据。
fs.readFile(filePath, function(err, data) {
if (err) {
// 处理错误
}
// 使用 data 对象
});
25) 什么是异步 API(Asynchronous API)?
Node.js 库的所有 API 都是异步的,意味着非阻塞。Node.js 基于事件循环的方式工作,不会等待 API 返回数据。Node.js 服务器在调用 API 后立即进入下一个 API,而 Node.js 的事件机制会响应前一个 API 调用。
26) 如何避免回调地狱?
要避免回调地狱,可以选择以下任一选项:
- 可以使用模块化。将回调拆分为独立的函数。
- 可以使用Promise。
- 可以使用生成器和 Promise 的yield。
27) Node.js 提供调试器吗?
是的,Node.js 提供了一个简单的基于 TCP 的协议和内置的调试客户端。要调试您的 JavaScript 文件,可以使用调试参数,然后跟上您要调试的 js 文件的名称。
语法:
node debug [script.js | -e "script" | <host>:<port>]
28) 什么是控制流函数?
控制流函数是通用的代码片段,在多个异步函数调用之间运行。
29) 控制流如何控制函数调用?
控制流执行以下任务:
- 控制执行顺序
- 收集数据
- 限制并发
- 调用程序的下一步
30) 在 Node 中可以访问 DOM 吗?
不可以,在 Node.js 环境中没有 DOM(Document Object Model),因为它是在浏览器中实现的。在 Node.js 中,您主要在服务器端执行 JavaScript 代码,处理 I/O 操作、文件系统等任务,而不涉及浏览器的页面渲染和 DOM 操作。
31) 使用事件循环可以异步执行哪些类型的任务?
Node.js 中的事件循环被设计用于高效地处理异步任务。以下是可以使用事件循环异步执行的一些任务类型:
- I/O 操作:读写文件,进行网络请求,与数据库交互等。
- 大量计算:执行消耗 CPU 的任务而不阻塞事件循环。
- 基于计时器的操作:在特定时间间隔或延迟后调度任务执行。
- 事件驱动编程:处理用户输入、传入请求和其他异步事件。
- 并行性:同时执行多个任务以利用可用的 CPU 核心。
32) Node.js 中的 REPL 是什么?
REPL 表示“Read Eval Print Loop”(读取-求值-输出-循环)。它是一个交互式编程环境,允许您执行 JavaScript 代码并立即查看结果。它类似于一个命令行界面,用于尝试代码片段、测试想法和实验 JavaScript 特性。Node.js 内置了一个 REPL 环境,您可以通过运行没有任何参数的 node
命令来访问它。
33) 解释 Node REPL 中使用的术语的任务。
在 Node 的 REPL 环境中,术语具有以下任务:
- Read(读取):读取用户输入并将其解析为 JavaScript 数据结构。
- Eval(求值):对解析后的数据结构进行求值。
- Print(输出):打印求值结果。
- Loop(循环):循环回到读取下一个用户输入的步骤,创建一个连续的交互循环。
34) 是否可以使用 Node REPL 评估简单表达式?
是的,可以使用 Node 的 REPL 评估简单表达式。您可以输入表达式并立即看到其结果。例如:
> 2 + 3
5
> 'Hello, ' + 'world!'
'Hello, world!'
> Math.sqrt(16)
4
35) 在 REPL 中下划线变量的用途是什么?
在 Node.js 的 REPL 中,下划线变量(_
)保存上次评估表达式的结果值。如果您想在后续计算或操作中重用结果,这可能会很有用。例如:
> 2 + 3
5
> _ * 2
10
36) Node.js 支持加密吗?
是的,Node.js 通过其内置的 crypto
模块支持加密功能。该模块提供了加密哈希函数、HMAC、加密、解密、数字签名等功能。它用于保护数据、生成安全令牌以及在网络上实现安全通信。
37) 什么是 npm?它的主要功能是什么?
npm 表示 Node Package Manager(Node 包管理器)。以下是 npm 的两个主要功能:
- 包管理:npm 允许开发人员轻松安装、管理和更新扩展 Node.js 应用程序功能的第三方包/模块。
- 依赖管理:npm 处理项目的依赖关系,确保所需的包被安装和维护。
- 版本管理:npm 允许您指定项目所需的包的版本,确保在不同环境中保持一致性。
- 脚本执行:npm 允许您使用
package.json
文件定义和运行脚本。 - 发布包:开发人员可以将自己的包发布到 npm 注册表供他人使用。
这些只是 npm 的核心功能之一。
38) 有哪些工具可以用于确保 Node.js 中的一致的编码风格?
为了确保 Node.js 项目中的一致的编码风格,可以使用代码 linting 和格式化工具。一些流行的工具包括:
- JSLint
- JSHint
- ESLint(最常用)
- Prettier(用于代码格式化)
这些工具有助于开发人员遵循编码标准,捕获错误,并在整个代码库中保持一致的风格。
39) 操作错误和程序员错误之间有什么区别?
操作错误是在运行时由外部环境或环境造成的问题。这些错误与应用程序的代码不直接相关,但可能影响其运行。示例包括网络故障、数据库不可用和服务器崩溃。
另一方面,程序员错误是开发人员所犯的编码错误。这些错误会导致应用程序出现错误和不正确的行为。示例包括语法错误、逻辑错误和错误的变量赋值。
40) 全局安装依赖和本地安装依赖之间有什么区别?
在 Node.js 中,全局安装和本地安装依赖具有不同的目的:
- 全局安装: 当您全局安装一个包时,它会在系统范围内安装,并且可以从终端的任何位置访问。全局包通常是您希望在不同项目中使用的命令行工具。您可以在
npm install
命令中使用-g
标志进行全局安装。 - 本地安装: 当您本地安装一个包时,它特定于特定项目,并存储在该项目的
node_modules
目录中。本地包是您的项目需要正常运行的依赖项。对于本地安装,不使用-g
标志。
本地安装是管理项目依赖项的最常见方式,因为它允许版本隔离和在不同项目之间保持可重现性。
41) Node.js 中的缓冲区类有什么用途?
Node.js 提供了缓冲区(Buffer)类,用于存储类似于整数数组的原始数据,但对应于 V8 堆外的原始内存分配。缓冲区是一个全局类,可以在应用程序中直接访问,无需导入缓冲区模块。缓冲区类的作用是因为纯 JavaScript 不兼容二进制数据。因此,在处理 TCP 流或文件系统时,必须处理八位字节流。
42) 在 Node.js 中,assert 的作用是什么?
Node.js 的 assert 模块是一种编写测试的方法。除非测试失败,否则在运行测试时不提供任何反馈。assert 模块提供了一组简单的断言测试,用于测试不变式。该模块主要用于 Node.js 的内部使用,但可以通过 require ('assert') 在应用程序代码中使用。示例如下:
var assert = require('assert');
function add(a, b) {
return a + b;
}
var expected = add(1, 2);
assert(expected === 3, 'one plus two is three');
43) 在 Node.js 中,什么是流(Streams)?
流是一种对象,用于从源读取数据并将数据写入目标。在 Node.js 中有四种类型的流:
- Readable(可读流): 用于读取操作。
- Writable(可写流): 用于写操作。
- Duplex(双工流): 可用于读写操作。
- Transform(转换流): 是一种特殊类型的双工流,其输出根据输入进行计算。
44) 什么是 Node.js 中的事件驱动编程?
在 Node.js 中,事件驱动编程意味着一旦 Node 启动其服务器,它会初始化其变量,声明函数,然后等待事件发生。这是 Node.js 相对于其他类似技术非常快速的一个原因。
45) 在 Node.js 中,事件(Events)和回调(Callbacks)之间有什么区别?
尽管事件和回调看起来相似,但区别在于回调函数在异步函数返回其结果时被调用,而事件处理基于观察者模式运作。每当事件被触发时,其监听函数开始执行。Node.js 通过 events 模块和 EventEmitter 类提供了多个内置事件和事件监听器。
46) 什么是 Punycode 在 Node.js 中的作用?
在 Node.js 中,Punycode 用于将一种类型的字符串转换为另一种类型。Punycode 是一种编码语法,用于将 Unicode(UTF-8)字符串转换为基本的 ASCII 字符串。由于主机名只能理解 ASCII 字符,因此从 Node.js 版本 0.6.2 开始,Punycode 被捆绑到默认的 Node 包中。对于其他 Node.js 版本,您可以使用 npm 安装 Punycode 模块并通过 require('punycode') 来访问它。
47) Node.js 中的 TTY 模块包含什么?
Node.js 的 TTY 模块包含 tty.ReadStream 和 tty.WriteStream 类。在大多数情况下,没有必要直接使用此模块。您可以使用 require('tty') 来访问这个模块。
48) Angular 和 Node.js 之间的关键区别是什么?
Angular 和 Node.js 之间的关键区别如下:
Angular | Node.js |
---|---|
Angular 是用于开发动态 Web 应用程序的结构化前端开发框架。 | Node.js 是用于编写 JavaScript 语言的应用程序的跨平台、运行时、服务器端环境。 |
Angular 完全使用 TypeScript 语言编写。 | Node.js 使用 C、C++ 和 JavaScript 语言编写。 |
Angular 用于构建单页、客户端端 Web 应用程序。 | Node.js 用于构建快速、可扩展的客户端和服务器端网络应用程序。 |
Angular 易于使用。开发人员需要将 Angular 文件添加到其应用程序中才能使用。 | Node.js 略微复杂。开发人员需要在计算机系统上安装 Node.js。 |
Angular 将 Web 应用程序拆分为 MVC 组件。其中模型和视图比其他 JavaScript 客户端框架中的简单得多。 | Node.js 生成数据库查询并利用 JavaScript 的事件驱动特性支持非阻塞操作,使平台更高效。 |
Angular 基于模型-视图-控制器(MVC)设计模式,并完全遵循该模式。 | Node.js 是单线程的。这意味着 Web 请求和处理在同一线程上运行。 |
Angular 是一个 Web 框架。 | Node.js 提供不同的 Web 框架,如 Socket.io、Hapi.js、Meteor.js、Express.js 和 Sails.js 等。 |
Angular 适用于创建高度活跃和交互式的 Web 应用程序。 | Node.js 适用于开发小型项目。 |
Angular 需要深入了解原型、作用域和其他各种 JavaScript 方面。 | Node.js 可以使开发人员在客户端和服务器端使用 JavaScript,因此他们可以专注于学习一种语言。 |
49) 操作错误和程序员错误之间的主要区别是什么?
操作错误和程序员错误之间最重要的区别在于操作错误不是错误,而是系统的问题,例如请求超时或硬件故障。另一方面,程序员错误是应用程序中的实际错误。
50) 你理解 Node.js 中的 EventEmitter 是什么?
在 Node.js 中,EventEmitter 是一个类,包含所有能够触发事件的对象。通过使用 eventEmitter.on() 函数,可以将命名事件附加到对象,并在对象触发事件时同步调用附加的函数。
示例:
const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.on('event', () => {
console.log('an event occurred!');
});
myEmitter.emit('event');
51) 在 Node.js 中,readFile 和 createReadStream 之间有什么区别?
在 Node.js 中,有两种方法可以读取和执行文件:readFile 和 createReadStream。
- readFile() 过程是一个完全缓冲的过程,仅当完整文件被推入缓冲区并读取时才返回响应。这个过程称为内存密集型过程,在处理大文件时,处理可能非常缓慢。
- 另一方面,createReadStream() 是一个部分缓冲的过程,将整个过程视为事件序列。整个文件被分成块,然后逐个处理并作为响应发送回来。完成此步骤后,它们最终从缓冲区中移除。与 readFile 过程不同,createReadStream 过程适用于大文件的处理。
52) 在 Node.js 中,Punycode 的概念是什么?
在 Node.js 中,Punycode 的概念用于将一种类型的字符串转换为另一种类型。Punycode 是一种编码语法,用于将 Unicode(UTF-8)字符串转换为基本的 ASCII 字符串。由于主机名只能理解 ASCII 字符,因此从 Node.js 版本 0.6.2 开始,Punycode 被捆绑到默认的 Node 包中。对于其他 Node.js 版本,您可以使用 npm 安装 Punycode 模块并通过 require('punycode') 来访问它。
53) 如何通过集群(clustering)来提高 Node.js 的性能?
由于 Node.js 应用程序在单个处理器上运行,因此默认情况下不能充分利用多核系统。集群用于解决此问题。集群模式用于启动多个 Node.js 进程,从而具有多个事件循环实例。当我们在 Node.js 应用程序中使用集群时,它会创建多个 Node.js 进程。但还有一个名为集群管理器的父进程,负责监视各个应用程序实例的健康情况。
54) Node.js 中的线程池是什么?哪个库处理它?
在 Node.js 中,线程池由 libuv 库处理。libuv 库是一个多平台的 C 库,支持异步 I/O 操作,如文件系统、网络和并发。