我正在 MDN 文档上做快速本地库教程,并想尝试在不使用回调方法的情况下返回对象。
当像这样将 id 的请求对象参数传递给 findById mongoose 方法并登录到控制台时,这是 bookinstance 的内容:
var bookinstance = BookInstance.findById(req.params.id);
像这样将 id 和回调函数传递给 findById 方法时
BookInstance.findOne({ _id: '63e17d2395d1d4e11604cf22' })
并登录到控制台,输出了预期的书籍实例对象:
BookInstance.findById(req.params.id, function(err, instance) {
if (err) {
next(err);
}
console.log('findById callback: ' + instance);
res.render("bookinstance_delete", {
title: "Book Instance Delete",
id: instance._id,
imprint: instance.imprint,
book: instance.book
})
})
这通常与 javascript 有关吗?这是我第一次接触express、node、mongoose以及所有这些基于javascript的框架和技术,它们似乎都大量使用回调。回调的目的只是为了有一种方式说,嘿,执行这个任务,当你完成后,执行这个任务?
当我没有使用回调时,返回的对象是对象和方法(findone),执行时会给我 bookinstance 对象和属性。那么回调函数会将该对象作为实例参数,执行它并返回该对象吗?这是怎么回事吗?
但是,在异步编程中,任务不需要等待每一行代码完成才能开始另一行代码。例如,为什么您的程序必须等待数据库查询完成才能读取文件或上传图像。这些耗时的任务肯定可以同时完成吗?在同步编程中,完成这些任务所需的时间被加在一起,但在异步编程中,您可以同时执行这些任务,所以您应该这样做。
但是随之而来的问题是如何知道每个异步何时完成。在同步编程中,您的代码只会移动到下一行代码。在 JavaScript/Node.js 异步编程中,有回调,它 本质上,只是用结果调用的另一个函数 异步操作。
您似乎已经掌握了这个概念:
所以回调的目的只是为了有一种方式说,嘿,执行这个任务,当你完成后,执行这个任务?
回调地狱回调模式只是 JavaScript 中的几种设计模式之一,可以处理异步任务,但它们也有其缺点 -
。 在现代 Node.js 中,我们有更新的设计模式,可以使用
Promises和 async/await 处理控制流。它们具有更好的语法,并且更易于阅读、编写和调试。由于 Node.js 是单线程,这些较新的设计模式使得运行不会阻塞单线程的响应式 Web 应用程序变得更加简单。 上面使用回调模式的示例:
findById callback: {
_id: new ObjectId("63e17d2395d1d4e11604cf22"),
book: new ObjectId("63e17d2395d1d4e11604cf16"),
imprint: 'New York Tom Doherty Associates, 2016.',
status: 'Available',
due_back: 2023-02-06T22:20:19.928Z,
__v: 0
}
是一种非常过时的方法,您现在找到的所有文档都概述了
BookInstance.findById(req.params.id, function(err, instance) {...});
或
Promises
模式。虽然 mongoose 查询不是 Promises,但您仍然可以使用带有 async/await
和
then
块的 Promises 实现:catch
这是
BookInstance.findById(req.params.id).then((doc) => {
console.log('Found Instance: ', doc);
})
.catch((err) => {
console.log(err);
});
模式:
async/await
一般来说,您会发现 mongoose 和 Node.js 的一个问题是,如果在进行数据库查询时不使用
app.get('/books/:id', async (req, res) => { // < Note the use of async keyword
try {
const result = await BookInstance.findById(req.params.id); // < Note the use of await keyword
console.log(result);
} catch(err) {
console.log(err);
}
});
或
Promises
模式,您将遇到意想不到的结果。例如你写道:
当我没有使用回调时,返回的对象是对象和方法(findone),这可能适用于一个小型查询,但如果集合中有数千或数百万个文档,并且您对它们执行了查询,则您的脚本实际上可能会在查询完成之前结束,并且不会返回任何文档。运行查询可能需要 200 毫秒,但您的脚本从开始到结束运行只花了 150 毫秒。如果没有回调、Promise 或 async/await,您的代码就会移至末尾,而您将无法从数据库中获得结果。