📜  Node.js 中的回调地狱是什么?

📅  最后修改于: 2022-05-13 01:56:18.627000             🧑  作者: Mango

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() 来简化和更好地使用回调。