Понимание различий в двух фрагментах асинхронного кода - PullRequest
0 голосов
/ 13 ноября 2018

Я пытался испачкать руки на продвинутых концепциях NodeJS Стивена Гриндера.

Пытаясь научить простым основам 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 я считаю, что они оба работают асинхронно, я подумал, что порядок не имеет значения.

Может кто-нибудь сказать мне, что я упускаю или не могу понять?

Ответы [ 3 ]

0 голосов
/ 21 ноября 2018

Поскольку ОП просит понять разницу, а не исправлять код:

express запускает функцию обработчика запросов и отлавливает синхронные ошибки (они становятся ошибками http500). Он ничего не делает с обещанием, возвращенным из асинхронной функции, и не использует внутреннее ожидание, поэтому вы не получаете бесплатную обработку ошибок для асинхронных функций. Все асинхронные ошибки необходимо перехватить внутри и передать обратному вызову next или обработать в вашем коде, отправив соответствующий код состояния и тело ошибки.

При возникновении ошибки JS останавливается и не выполняет больше строк в функции. Таким образом, если выдается ошибка из client.set, помещенного до res.send, строка с send не запускается и ответ не отправляется. Браузер должен продолжать ждать ответа до истечения времени ожидания.

С другой стороны - вы отправляете ответ до ошибки, поэтому вы получаете страницу, но ответ не заканчивается (я бы предположил, что соединение остается открытым, как если бы сервер собирался отправить больше), но с тех пор ранние версии браузеров Firefox начинают отображать HTML при загрузке, поэтому вы видите страницу, даже если браузер все еще ожидает завершения ответа.

0 голосов
/ 22 ноября 2018

Две задачи будут выполняться асинхронно, но порядок выполнения имеет значение.

client.set(req.user.id, JSON.stringify(blogs)) выполнение начинается первым, но поскольку вы не используете await, обещание не будет выполнено, но выполнение уже началось. После этого 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);
});
0 голосов
/ 17 ноября 2018

Порядок этих двух строк не имеет значения, но res.send не вызывается в случае, если client.set идет первым, значит, есть ошибка.Если в функции async возникает ошибка, это может привести к предупреждению UnhandledPromiseRejectionWarning, которое будет отображаться в консоли.

Существует несколько проблем с этим фрагментом.

Ошибка возникает дажеесли хотя client.set является асинхронным, то это означает, что client.set вызывает синхронную ошибку, которая не была обнаружена.

client.set не было обещано, но это должно происходить для правильного потока управления.Отсутствие аргумента обратного вызова может послужить причиной возникновения ошибки.

Как объяснено в в этом ответе , 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...