Как превратить функцию с колбэком в промис
Короткий ответ
Создайте new Promise и внутри колбэка вызовите resolve при успехе и reject при ошибке:
function loadData(id, callback) {
setTimeout(() => {
if (id < 0) callback(new Error('Invalid id'));
else callback(null, { id, title: 'Report' });
}, 50);
}
const loadDataAsync = (id) =>
new Promise((resolve, reject) => {
loadData(id, (error, data) => (error ? reject(error) : resolve(data)));
});
const data = await loadDataAsync(7);
console.log(data.title);
try {
await loadDataAsync(-1);
} catch (error) {
console.log(error.message);
}Результат:
Report
Invalid idКартинка в браузере
События вроде load и error так же превращаются в промис:
const loadImage = (src) =>
new Promise((resolve, reject) => {
const image = new Image();
image.onload = () => resolve(image);
image.onerror = () => reject(new Error(`Could not load ${src}`));
image.src = src;
});
const logo = await loadImage('/logo.png');
document.body.append(logo);В Node.js
В Node.js есть готовая функция promisify() для функций с колбэком в стиле (error, result):
import { promisify } from 'node:util';
function add(a, b, callback) {
setTimeout(() => callback(null, a + b), 10);
}
const addAsync = promisify(add);
console.log(await addAsync(2, 3));Результат:
5Частая ошибка
Ошибка, выброшенная внутри колбэка таймера, сама до reject() не дойдёт. Поймайте её и вызовите reject() сами, иначе промис будет ждать вечно.
const parseLater = (text) =>
new Promise((resolve, reject) => {
setTimeout(() => {
try {
resolve(JSON.parse(text));
} catch (error) {
reject(error);
}
}, 10);
});
console.log(await parseLater('{bad').catch((error) => error.name));Результат:
SyntaxErrorФункции из этого ответа
- Promise — Обещание результата, который будет готов позже: успех или ошибка.
- async function — Функция, которая всегда возвращает промис и внутри которой можно использовать await.