我试图弄清Stephen Grinder的高级NodeJS概念。
Stephen尝试讲授Redis的基础知识,做了类似的事情
app.get('/api/blogs', requireLogin, async (req, res) => {
//This time we are setting
const redis = require('redis')
const redisURL = 'redis://127.0.0.1:6379';
const client = redis.createClient(redisURL);
const util = require('util')
client.get = util.promisify(client.get)
//We are checking if we have ever fetched any blogs related to the user with req.user.id
const cachedBlog = await client.get(req.user.id)
//if we have stored list of blogs, we will return those
if (cachedBlog) {
console.log(cachedBlog)
console.log("Serving from Cache")
return res.send(JSON.parse(cachedBlogs))
} //this is JSONIFIED as well so we need to convert it into list of arrays
console.log("serving from Mongoose")
//if no cache exsist
const blogs = await Blog.find({_user: req.user.id})
//blogs here is an object so we would need to stringfy it
res.send(blogs);
client.set(req.user.id, JSON.stringify(blogs))
})
它可以正常工作,但如果更改顺序,则可以在最后两行中
client.set(req.user.id, JSON.stringify(blogs))
res.send(blogs);
它不显示我的博客。
由于在API中,我正在考虑将它们都异步运行,因此我认为顺序无关紧要。
谁能告诉我我想念或无法理解的内容?
答案 0 :(得分:1)
这两行的顺序无关紧要,但是如果res.send
首先出现,则不会调用client.set
,这意味着存在错误。如果async
函数发生错误,则可能会导致UnhandledPromiseRejectionWarning
警告,该警告将在控制台中显示。
此代码段存在几个问题。
即使client.set
是异步的,也会发生错误,这表明client.set
导致了未被捕获的同步错误。
client.set
并未被承诺,但应该用于正确的控制流程。没有提供回调参数可能是导致错误的原因。
如this answer中所述,Express不支持承诺,应明确处理所有拒绝,以进行正确的错误处理。
所有常见的代码,例如require
都超出了中间件功能。应该是:
const redis = require('redis')
const redisURL = 'redis://127.0.0.1:6379';
const client = redis.createClient(redisURL);
const util = require('util')
client.get = util.promisify(client.get)
client.set = util.promisify(client.set)
app.get('/api/blogs', requireLogin, async (req, res, next) => {
try {
const cachedBlog = await client.get(req.user.id)
if (cachedBlog) {
return res.send(JSON.parse(cachedBlogs))
}
const blogs = await Blog.find({_user: req.user.id});
await client.set(req.user.id, JSON.stringify(blogs));
res.send(blogs);
} catch (err) {
next(err);
}
})
大多数流行的库都有与之对应的承诺,它们允许跳过样板承诺代码,这也适用于redis
。
答案 1 :(得分:1)
由于OP要求了解两者之间的差异,因此请不要修改代码:
express运行请求处理程序功能并捕获同步错误(它们变为http500错误)。它对异步函数返回的承诺不做任何事情,并且在内部不使用await,因此您不会免费获得异步函数的错误处理。所有异步错误都必须被捕获并传递到next
回调中,或者通过发送适当的状态代码和错误正文在代码中进行处理。
发生错误时,JS停止并且不再执行该函数中的任何更多行。因此,如果从client.set
之前的res.send
抛出错误,则发送send的行将不会运行,也不会发送任何响应。浏览器应继续等待响应,直到超时。
另一种方法-您在错误之前发送响应,这样您就可以得到页面,但是响应不会结束(我假设连接保持打开状态,就像后端将发送更多内容一样),但是从那以后早期版本的Firefox浏览器会在下载HTML时开始呈现HTML,因此即使浏览器仍在等待响应完成,您也会看到一个页面。
答案 2 :(得分:1)
这两个任务将异步运行,但是执行顺序很重要。
client.set(req.user.id, JSON.stringify(blogs))
首先开始执行,但是由于您不使用等待,承诺不会被解决,但是执行已经开始。
之后res.send()
将执行。
您未收到响应意味着client.set(req.user.id, JSON.stringify(blogs))
的执行中存在一些错误。
使用Try catch块来跟踪此错误(如其他答案所述)。
您还可以在代码中添加这些行,以捕获其他“ unhandledRejection”或“ uncaughtException”错误(如果有)。
process.on('unhandledRejection', (err) => {
logger.error('An unhandledRejection error occurred!');
logger.error(err.stack)
});
process.on('uncaughtException', function (err) {
logger.error('An uncaught error occurred!');
logger.error(err.stack);
});