Библиотека bcrypt.js реализует асинхронные операции хеширования и
проверки паролей через промисы, что позволяет выстраивать
последовательные цепочки обработки без вложенных колбэков. Основные
методы, такие как hash и compare, возвращают
Promise, что делает их совместимыми с .then()
и async/await.
При работе с цепочками важно понимать, что каждая операция в bcrypt является вычислительно затратной. Это означает, что корректное управление последовательностью вызовов и обработкой ошибок напрямую влияет на стабильность всего потока аутентификации.
Пример базовой цепочки хеширования и последующего сравнения:
bcrypt.hash(password, 10)
.then((hash) => {
return bcrypt.compare(password, hash);
})
.then((isMatch) => {
console.log(isMatch);
});
Каждый .then() получает результат предыдущего шага и
возвращает новый промис. Таким образом формируется линейный поток
обработки данных, где результат одного этапа становится входом
следующего.
В реальных сценариях цепочки редко ограничиваются двумя шагами. Чаще они включают подготовку данных, хеширование, сохранение в базу и последующую проверку.
bcrypt.hash(password, 12)
.then((hash) => {
return saveUser({ username, passwordHash: hash });
})
.then((user) => {
return bcrypt.compare(password, user.passwordHash);
})
.then((result) => {
return result;
});
Каждый .then() не только получает результат, но и обязан
возвращать либо значение, либо новый промис. Отсутствие
return приводит к разрыву цепочки и потере управляемости
потоком выполнения.
Любая операция bcrypt может завершиться отклонением промиса. Причины включают некорректные входные данные, повреждённые хеши или внутренние ошибки вычислений.
Классическая обработка ошибок реализуется через
.catch():
bcrypt.hash(password, 10)
.then((hash) => bcrypt.compare(password, hash))
.then((result) => {
console.log(result);
})
.catch((err) => {
console.error(err);
});
.catch() перехватывает любую ошибку, возникшую на любом
этапе цепочки. Это обеспечивает централизованную обработку отказов без
необходимости проверять каждый шаг отдельно.
Ошибка, возникшая внутри .then(), автоматически
превращается в отклонённый промис. Это позволяет явно управлять
условиями прерывания цепочки.
bcrypt.hash(password, 10)
.then((hash) => {
if (!hash) {
throw new Error('Hash generation failed');
}
return hash;
})
.then((hash) => bcrypt.compare(password, hash))
.catch((err) => {
console.error('Ошибка:', err.message);
});
Выбрасывание исключения внутри .then() эквивалентно
Promise.reject(). Это важный механизм для контроля логики
валидации промежуточных результатов.
Ошибки в цепочке распространяются вниз до первого обработчика
.catch(). Все промежуточные .then()
пропускаются до момента перехвата.
bcrypt.hash(password, 10)
.then(() => {
throw new Error('Ошибка на этапе цепочки');
})
.then(() => {
// этот код не выполнится
})
.catch((err) => {
console.log('Перехвачено:', err.message);
});
Такой механизм позволяет строить линейные потоки без необходимости проверять результат каждого шага вручную.
Цепочка может содержать несколько уровней обработки ошибок, если требуется локальная и глобальная реакция на сбои.
bcrypt.hash(password, 10)
.then((hash) => {
return bcrypt.compare(password, hash)
.catch((err) => {
console.log('Ошибка сравнения');
throw err;
});
})
.then((result) => {
console.log(result);
})
.catch((err) => {
console.log('Глобальная обработка:', err.message);
});
Локальный .catch() перехватывает ошибку только внутри
вложенного промиса, после чего ошибка может быть повторно выброшена для
внешнего уровня.
Хотя Promise-цепочки остаются базовым механизмом,
async/await упрощает чтение и управление ошибками через
try/catch.
async function checkPassword(password, hash) {
try {
const result = await bcrypt.compare(password, hash);
return result;
} catch (err) {
console.error(err);
}
}
Под капотом async/await использует те же промисы, но
скрывает необходимость явного построения цепочек
.then().
Неправильное использование промисов в bcrypt.js чаще всего связано с потерей возврата значений:
bcrypt.hash(password, 10)
.then((hash) => {
bcrypt.compare(password, hash); // отсутствует return
})
.then((result) => {
// result будет undefined
});
Отсутствие return разрывает поток данных и приводит к
неконтролируемому состоянию цепочки.
Другой тип ошибки — игнорирование обработки отклонений:
bcrypt.hash(password, 10)
.then((hash) => bcrypt.compare(password, hash));
Без .catch() любая ошибка останется необработанной, что
может привести к аварийному завершению процесса в средах Node.js.
Каждый .then() должен возвращать либо:
Несоблюдение этого правила приводит к потере связности цепочки:
bcrypt.hash(password, 10)
.then((hash) => {
return { hash };
})
.then((data) => {
return bcrypt.compare(password, data.hash);
});
Явное структурирование промежуточных данных повышает предсказуемость цепочки и упрощает отладку.
bcrypt является ресурсоёмкой функцией, поэтому длинные цепочки с последовательными вызовами могут увеличивать задержки ответа. При обработке большого числа запросов важно избегать избыточных последовательных операций внутри одной цепочки.
Параллелизм в bcrypt ограничен характером алгоритма, поэтому оптимизация чаще достигается не через распараллеливание, а через корректное построение минимально необходимой цепочки промисов.