Node.js 中的回调地狱是什么?
要知道什么是回调地狱,我们必须从同步和异步 Javascript 开始。
什么是同步 Javascript?
在同步 Javascript 中,当我们运行代码时,浏览器会尽快返回结果。一次只能进行一项操作,因为它是单线程的。因此,在执行操作时,所有其他进程都会暂停。
什么是异步 Javascript?
- Javascript 中的某些函数需要 AJAX,因为某些函数的响应不是立即的。这需要一些时间,并且下一个操作无法立即开始。它必须等待函数在后台完成。在这种情况下,回调需要是异步的。
- 有一些外部 Javascript Web API 允许 AJAX——异步 Javascript 和 XML。
在 AJAX 中,可以同时执行许多操作。
什么是回调?
- 回调只是需要一些时间才能产生结果的函数。
- 通常这些异步回调(async 异步的缩写)用于访问数据库中的值、下载图像、读取文件等。
- 由于这些需要时间来完成,我们既不能继续下一行,因为它可能会抛出一个错误,说不可用,我们也不能暂停我们的程序。
- 所以我们需要存储结果并在完成时回调。
什么是回调地狱?
这是由复杂的嵌套回调编码引起的一个大问题。在这里,每个回调都接受一个参数,该参数是先前回调的结果。这样一来,代码结构看起来就像一个金字塔,难以阅读和维护。此外,如果一个函数出现错误,那么所有其他函数都会受到影响。
示例:这是典型的回调地狱的示例。
app.get("/details", function (req, res) {
var name = req.query.name;
console.log(name);
Scopus.find({ name: name },
{ '_id': 0, 'authorId': 1 },
function (err, result) {
if (err) { }
else {
var searchResult = result[0]["authorId"];
console.log(searchResult);
var options = {
url: "https://api.elsevier.com/content/author/author_id/"
+ searchResult + "?apiKey",
headers: { 'Accept': 'application/json' }
};
request(options, function (error, response, body) {
if (error) {
// Print the error if one occurred
console.error('error in Authors :', error);
// Print the response status code if a response was received
console.log('statusCode:', response && response.statusCode);
res.send("error")
}
else if (!error) {
var jsonObj = JSON.parse(body);
if (jsonObj['author-retrieval-response'] == undefined) {
res.send("No details");
}
else {
var reqData = jsonObj['author-retrieval-response'][0];
var authprofile = reqData["author-profile"]
var names = authprofile["preferred-name"]["indexed-name"]
console.log(names);
var citation = reqData["coredata"]["citation-count"];
var query = { authorId: searchResult };
Scopus.findOneAndUpdate(query, {
name: names,
citationCount: citation
}, function (err, doc, res) {
if (err) {
console.log("error");
}
else {
console.log("success");
}
})
res.render("details", { data: reqData });
}
}
});
}
})
});
您会注意到嵌套回调看起来像一个金字塔,难以理解。
如何逃离回调地狱?
- JavaScript 提供了一种从回调地狱中逃脱的简单方法。这是由事件队列和承诺完成的。
- Promise 是从任何异步函数返回的对象,可以根据前一个函数的结果向其中添加回调方法。
- Promise 使用 .then() 方法来调用异步回调。我们可以根据需要链接任意数量的回调,并且顺序也得到严格维护。
- Promise 使用 .fetch() 方法从网络中获取对象。它还使用 .catch() 方法在任何块失败时捕获任何异常。
- 所以这些 Promise 被放入事件队列中,这样它们就不会阻塞后续的 JS 代码。同样,一旦返回结果,事件队列就会完成其操作。
- 还有其他有用的关键字和方法,如 async、wait、settimeout() 来简化和更好地使用回调。