Функция продолжает выполнение даже после возврата - PullRequest
0 голосов
/ 12 июля 2020

Мой вопрос прост: когда я запускаю следующий код и проверяю БД, я обнаруживаю, что пользователь успешно удален, это означает, что User.findOneAndDelete выполняется, обещание выполнено, и я ожидаю увидеть { success: 'user_deleted' } в ответ; однако я получаю { error: 'user_not_found' }, что должно происходить ТОЛЬКО в том случае, если User не существует, что здесь не так, потому что код внутри блока IF выполняется согласно моим наблюдениям в БД.

User.exists({ username}).then(exists => {
    if (exists) {
      User.findOneAndDelete({ username }).then(() => {
        res.json({ success: 'user_deleted' });
        return;
      }
      ).catch(err => {
        res.json({ error: 'user_delete_fail' });
        return;
      })
    };
    res.json({ error: 'user_not_found' })
    return;
  });

Теперь, чтобы решить эту проблему, я попытался добавить оператор else вместо неявного способа, которым я делал это раньше, и он работал, как ожидалось, и я получил в ответе `{success: 'user_deleted'}.

User.exists({ username}).then(exists => {
    if (exists) {
      User.findOneAndDelete({ username }).then(() => {
        res.json({ success: 'user_deleted' });
        return;
      }
      ).catch(err => {
        res.json({ error: 'user_delete_fail' });
        return;
      })
    } else {
      res.json({ error: 'user_not_found' })
      return;
    };
  });

Мой вопрос: почему такое поведение происходит? Почему выполнение уже перескакивает в конец функции? И почему, когда он переходит в нижнюю часть функции и отвечает, как происходит удаление и пользователь удаляется в БД, я здесь совершенно запутался.

EDIT: он также ведет себя так, как ожидалось, когда я конвертирую родительскую функцию для функции async и используйте await для операции с базой данных.

Ответы [ 2 ]

2 голосов
/ 12 июля 2020

Проблема с вашим кодом - это последний вызов res.json({ error: 'user_not_found' }).

Если вы внимательно посмотрите, эта строка запускается даже до того, как срабатывает внутренний запрос на удаление, поскольку внутренний запрос является асинхронным.

Итак, в первом сценарии функция всегда возвращает ответ независимо от того, существует пользователь или нет.

добавление else в ваш блок кода в основном выполняет either this or that logi c, поэтому, если пользователь существует, res.json({ error: 'user_not_found' }) никогда не получит вызывается.

РЕДАКТИРОВАТЬ: Альтернативный код с использованием Asyn c -Await

Использование async-await в этом случае имеет больше смысла, поскольку это упрощает код, проверьте следующее код, который должен делать именно то, что вы хотите, без использования else.

Он также избегает вложенности, что упрощает код

User.exists({ username }).then(async exists => {
    try {
        if (exists) {
            // this await will remove the need of inner promise chaining
            await User.findOneAndDelete({ username });
            res.json({ success: 'user_deleted' });
        }
        // in this case, this will no longer be performed before delete query
        res.json({ error: 'user_not_found' });
    } catch (error) {
        res.json({ error: 'user_delete_fail' });
    }
});

PS - Вы можете иметь аналогичный async-await для User.exists API при условии, что его родительская функция помечена как async.

Надеюсь, это поможет.

1 голос
/ 12 июля 2020

findOneAndDelete возвращает Promise, который не блокирует выполнение оставшегося кода (кроме случаев, когда, как вы указали, функция async и вы ее ждете). Кроме того, вы не возвращаетесь из ветки if (return внутри then будет возвращаться только из обратного вызова в then), и, следовательно, оставшийся снаружи код будет выполнен в любом случае. Вероятно, это работает, только если вы ждете (без return), потому что ответ уже отправлен в точке.

...