作者 • Dhanjiv Pandey • 本文出处 • 已获得中译授权
• 作者twitter
• 译者主页
译者按: 2018年的文章,其中部分问题放在今天仍然不算过时。
# Q-11:什么是回调地狱?
一开始,你可以在了解回调后表扬它。回调地狱是大量嵌套的回调,这使得代码难以阅读和维护。
让我们看看下面的代码示例:
downloadPhoto('http://coolcats.com/cat.gif', displayPhoto)
function displayPhoto (error, photo) {
if (error) console.error('Download error!', error)
else console.log('Download finished', photo)
}
console.log('Download started')
在这种情况下,Node.js首先声明 displayPhoto
函数。此后,它将调用 downloadPhoto
函数并传递 displayPhoto
函数作为其回调。最后,该代码在控制台上显示Download started
。仅在 downloadPhoto
完成其所有任务的执行后,才会执行 displayPhoto
。
# Q-12:如何避免在Node.js出现回调地狱?
Node.js在内部使用单线程事件循环来处理排队的事件。但是,如果任务的运行时间比预期的长,则此方法可能导致阻塞整个过程。
Node.js通过合并回调(也称为higher-order
函数)解决了此问题。因此,只要长时间运行的进程完成执行,就会触发关联的回调。通过这种方法,它可以允许代码在长时间运行的任务之后继续执行。
然而,上述解决方案看起来非常有前途。但是有时候,这可能会导致复杂且无法读取的代码。更多的情况下它会导致返回的回调链将更长。
由于这种前所未有的复杂性,调试代码非常困难,可能会耗费大量时间。有四种解决方案可以解决回调地狱问题。
1. 程序模块化.
它建议将逻辑分为较小的模块。然后从主模块将它们连接在一起以达到所需的结果。
2. 使用 async 机制.
它是一个广泛使用的Node.js模块,提供了一个连续的执行流。
异步模块具有 async.waterfall
API,该API使用下一个回调将数据从一个操作传递到另一操作。
另一个异步API async.map
允许并行遍历项目列表,并使用另一个结果列表进行回调。
使用异步方法,调用者的回调仅被调用一次。这里的调用者是使用async模块的主方法。
3. 使用 promises 机制.
Promises 提供了另一种编写异步代码的方法. 它们要么返回执行结果,要么返回 error/exception
.实现promise需要使用 then()
函数,该函数等待 promise
对象返回。它带有两个可选参数,是两个函数。根据promise的状态,只有一个会被调用。如果promise得到实现,则将执行第一个函数调用。但是,如果Promise被拒绝,则将调用第二个函数。
4. 使用 generators.
Generators是轻量级的routines,它们通过yield关键字使函数等待并恢复。生成器函数使用特殊语法function* ()
。他们还可以使用诸如promises或thunks
之类的结构来暂停和恢复异步操作,并将同步代码转换为异步代码。
# Q-13:你能用Nodejs创建HTTP服务器吗,解释一下你使用的代码?
是的,我们可以在Node.js中创建HTTP Server。我们可以使用http-server
命令来执行此操作。
以下是示例代码:
var http = require('http');
var requestListener = function (request, response) {
response.writeHead(200, {'Content-Type': 'text/plain'});
response.end('Welcome Viewers\n');
}
var server = http.createServer(requestListener);
server.listen(8080); // The port where you want to start with.
# Q-14:Nodejs、AJAX和jQuery之间的区别是什么?
Node.js,AJAX和jQuery之间的一个共同特征是它们都是JavaScript的高级实现。但是,它们的用途完全不同。
Node.js –
它是用于开发客户端服务器应用程序的服务器端平台。例如,如果我们必须构建一个在线员工管理系统,那么我们就不会使用客户端JS来实现它。但是Node.js当然可以做到这一点,因为它运行在类似于Apache的服务器上,而不是运行在浏览器上。
AJAX (aka Asynchronous Javascript and XML) –
它是一种客户端脚本技术,主要用于呈现页面内容而不刷新页面。
jQuery –
它是著名的JavaScript模块,对AJAX、DOM遍历、循环等进行了补充。这个库提供了许多有用的函数来帮助JavaScript开发。不过,使用它不是强制性的,它还管理跨浏览器的兼容性,所以可以帮助您生成高度可维护的web应用程序。
# Q-15:Node.js中的Globals是什么?
Node.js中有三个关键字构成Globals。它们是 Global
,Process
和Buffer
。
Global
Global关键字表示全局名称空间对象。它充当所有其他global
对象的容器。如果我们输入console.log(global)
,它会全部打印出来。
关于全局对象要注意的重要一点是,并非所有对象都在全局范围内,其中一些属于模块范围。因此,不使用var关键字声明它们或将它们添加到Global对象是明智的。
使用var关键字声明的变量在模块中变为局部变量,而那些没有声明的变量会订阅到全局对象。
Process
它也是全局对象之一,但包含将同步功能转换为异步回调的其他功能。从代码中的任何地方访问它都没有限制。它是EventEmitter类的实例。每个node application object
都是Process对象的一个实例。
它主要返回有关应用程序或环境的信息。
– 获取Node应用程序的执行路径.
– 获取当前正在运行的Node版本.
– 获取服务器平台.
其他一些有用的处理方法如下:
– 了解node程序使用的内存.
– 附加一个将在下一个循环中调用的回调函数。它会导致函数延迟执行.
Buffer
Buffer是Node.js中处理二进制数据的一个类。它类似于整数列表,但是存储在V8堆之外的原始内存中。
我们可以将JavaScript字符串对象转换为Buffers。但这需要显式地声明编码类型。
– 指定7位ASCII数据.
– 表示多字节编码的Unicode字符集.
– 表示2或4个字节,用小尾数编码的Unicode字符.
– 用于Base64字符串编码.
– 将每个字节编码为两个十六进制字符.
这是使用Buffer类的语法:
> var buffer = new Buffer(string, [encoding]);
上面的命令将分配一个新的buffer来保存默认编码为 utf8
的字符串。但是,如果您想将string
写入现有的buffer object
,请使用以下代码行:
> buffer.write(string)
buffer 还提供其他方法,例如readInt8
和writeUInt8
,该方法允许从各种类型的数据读/写到 buffer。
# Q-16:如何在Node.js中加载HTML?
要在Node.js中加载HTML,我们必须将HTML代码中的 Content-type
从 text/plain 更改为 text/html。
让我们看一个在web服务器中创建静态文件的示例:
fs.readFile(filename, "binary", function(err, file) {
if (err) {
response.writeHead(500, {"Content-Type": "text/plain"});
response.write(err + "\n");
response.end();
return;
}
response.writeHead(200);
response.write(file, "binary");
response.end();
});
现在,我们将修改此代码以加载HTML页面而不是纯文本。
fs.readFile(filename, "binary", function(err, file) {
if (err) {
response.writeHead(500, {"Content-Type": "text/html"});
response.write(err + "\n");
response.end();
return;
}
response.writeHead(200, {"Content-Type": "text/html"});
response.write(file);
response.end();
});
# Q-17:Node.js中的EventEmitter是什么?
Node.js中的事件模块允许我们创建和处理自定义事件。事件模块包含 EventEmitter
类,可用于引发和处理自定义事件。可通过以下代码进行访问:
// 导入事件模块
var events = require('events');
// 创建一个eventEmitter对象
var eventEmitter = new events.EventEmitter();
当EventEmitter实例遇到错误时,它将触发 error
事件。添加新的侦听器时,将触发 newListener
事件,而删除侦听器时,将触发 removeListener
事件。
EventEmitter提供多个属性,例如 on
和 emit
。on
属性用于将函数绑定到事件,emit
用于触发事件。
# Q-18:Node.js中有几种类型的流?
Node.js中的Stream是允许以连续方式从源读取数据或将数据写入特定目标的对象。在Node.js中,有四种类型的流:
– 这是用于读取操作的Stream.
– 它简化了写的操作.
– 此流可用于读取和写入操作.
– 它是双工流的一种形式,它根据可用的输入执行计算.
上面讨论的所有流都是 EventEmitter
类的实例。由流抛出的事件随时间而变化。一些常用事件如下:
– 当有可供读取的数据时,将触发此事件.
– 没有更多数据可读取时,Stream将触发此事件.
– 当读取或写入数据时出现任何错误时触发此事件.
– 当所有数据刷新到底层系统后,将触发此事件.
# Q-19:列出并解释重要的REPL命令?
下面是一些最常用的REPL命令:
<.help>
– 显示所有命令的帮助.
– 它显示所有可用命令的列表.
– 它的用途是确定之前在REPL中执行了什么命令.<.save filename>
– 将当前的REPL会话保存到文件中.<.load filename>
– 在当前REPL会话中加载指定的文件.
– 用于终止当前命令.
– 退出REPL.
– 此命令执行从REPL退出.<.break>
– 从多行表达式导出.<.clear>
– 从多行表达式退出.
# Q-20:Node.js中的NPM是什么?
NPM 是Node的一个包管理器,也是一个平台。它提供以下两个主要功能:
- 它作为node.js包/模块的在线存储库,这些包/模块存在于
(译者:不应该是npmjs.com吗?)中。 - 它作为命令行工具来安装包,执行Node.js软件包的版本管理和依赖关系管理。
NPM与Node.js捆绑在一起安装。我们可以使用以下命令:
# 验证它的版本
$ npm --version
# 使用以下命令帮助安装任何Node.js模块。
# $ npm install
# 例如,下面是安装一个著名的Node.js web框架模块express-的命令
$ npm install express