Понимание странной ошибки с промисами и undefined var - PullRequest
0 голосов
/ 17 июня 2020

Я только что обнаружил, что мой API делает странные вещи, когда 2 запроса запускаются почти одновременно.

Я понял, что проблема заключалась в том, что у меня отсутствовало объявление «var» перед моим «пользователем» "переменная ниже, но мне действительно интересно узнать о проблеме root, которая вызвала ошибку, описанную ниже:

У меня есть две конечные точки API, которые вызывают ту же функцию, как показано ниже:

router.get('/refresh_session_token', function (req, res) {

   let user_id = req.body.user_id // The value sent is 8

   findUserWithId(user_id)
    .then(user_data => {
      user = user_data // I forgot 'var' here
    })
    .then(() => {
      console.log(user) // This should always show user data from user_id = 8
    })
}


router.get('/resend_invite', function (req, res) {

   let user_id = req.body.user_id // The value sent is 18

   findUserWithId(user_id)
    .then(user_data => {
      user = user_data // I forgot 'var' here
    })
    .then(() => {
      console.log(user) // This should always show user data from user_id = 18
    })
}

const findUserWithId = (id) => {
  return knex.raw(`SELECT * FROM users WHERE id = ?`, [id]).then((data) => data.rows[0])
}

Весь этот код находится в том же файле, который я экспортирую через module.exports = router;

Я обнаружил, что если я активирую конечные точки / refresh_session_token и / Resend_invite почти в одно и то же время каждый с двумя разными user_id, иногда мой console.log возвращает тот же результат для обоих, как если бы я использовал один и тот же user_id.

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

Есть идеи?

1 Ответ

2 голосов
/ 17 июня 2020

Если вы не объявляете свою переменную и не запускаете свой модуль в режиме Javascript strict, то первое присвоение этой переменной с помощью:

user = user_data

создает automati c глобальная переменная с именем user. Это означает, что ваши два маршрута затем используют одну и ту же переменную.

И, поскольку оба ваших маршрута имеют асинхронные операции в них, даже с однопоточностью вещей, ваши два маршрута все еще могут быть в полете. одновременно и оба пытаются использовать одну и ту же глобальную переменную. Один маршрут перезапишет значение другого. Это катастрофа для серверного кода, потому что обычно ошибка не проявляется до тех пор, пока вы не попадете в производство, и будет действительно очень сложно найти воспроизводимый случай.

Лучший ответ здесь - всегда запустите свой код в строгом режиме, и тогда интерпретатор JS сделает это ошибкой, и вам никогда не разрешат запускать свой код таким образом. Ошибка будет обнаружена очень быстро и легко.

Тогда, очевидно, всегда объявляйте переменные с помощью let или const. Существует очень и очень мало причин использовать var больше, поскольку let и const дают вам больший контроль над областью вашей переменной.

Чтобы запустить ваш модуль в строгом режиме, вставьте это :

'use strict';

перед любыми другими операторами Javascript.

Или используйте что-то вроде TypeScript, который не позволяет делать небрежные вещи, например не объявлять переменные.

...