Плагин eslint-plugin-promise предназначен для
статического анализа кода, связанного с использованием промисов в
JavaScript. Его основная цель — выявление ошибок управления
асинхронностью, некорректных цепочек then/catch, а также
анти-паттернов, которые приводят к утечкам ошибок, «зависшим» промисам и
непредсказуемому поведению.
Проблемная зона, на которую ориентирован плагин, — это не синтаксис
промисов как таковой, а логика их использования: возвраты из
then, обработка ошибок, вложенность цепочек и смешивание
callback- и promise-подходов.
Плагин подключается стандартным способом через npm:
npm install eslint-plugin-promise --save-dev
После установки он добавляется в конфигурацию ESLint:
{
"plugins": ["promise"],
"extends": ["plugin:promise/recommended"]
}
Использование plugin:promise/recommended включает набор
правил, ориентированных на безопасное использование промисов, без
необходимости ручной настройки каждой проверки.
Альтернативный вариант — ручная конфигурация:
{
"plugins": ["promise"],
"rules": {
"promise/catch-or-return": "error",
"promise/always-return": "error"
}
}
Статический анализ в eslint-plugin-promise строится
вокруг нескольких ключевых наблюдений:
then должны быть линейными и
предсказуемыми;catch считается критической проблемой;Одно из центральных правил — promise/catch-or-return.
Оно контролирует, чтобы каждый промис:
catch.Типичный анти-паттерн:
function loadData() {
fetch("/api/data")
.then(response => response.json());
}
Проблема заключается в том, что ошибка запроса не обрабатывается, и промис «теряется» — невозможно отследить сбой.
Корректные варианты:
function loadData() {
return fetch("/api/data")
.then(response => response.json())
.catch(err => {
console.error(err);
});
}
или
function loadData() {
return fetch("/api/data")
.then(response => response.json());
}
promise/always-return контролирует, что внутри цепочек
then всегда явно возвращается значение или промис.
Нарушение:
fetch("/api/data")
.then(response => {
if (!response.ok) {
throw new Error("Error");
}
response.json();
});
Проблема — отсутствие return, что приводит к возвращению
undefined.
Исправленный вариант:
fetch("/api/data")
.then(response => {
if (!response.ok) {
throw new Error("Error");
}
return response.json();
});
Это правило критично для поддержания корректной цепочки промисов, где каждое звено передаёт результат дальше.
promise/no-nesting запрещает вложенные вызовы промисов,
когда внутри одного then создаётся новый
then.
Проблемный пример:
fetch("/api/user")
.then(user => {
return fetch(`/api/orders/${user.id}`)
.then(orders => {
return orders.json();
});
});
Проблема — глубокая вложенность, ухудшающая читаемость и усложняющая обработку ошибок.
Рекомендуемый вариант — плоская цепочка:
fetch("/api/user")
.then(user => fetch(`/api/orders/${user.id}`))
.then(orders => orders.json());
promise/no-return-wrap выявляет лишнюю обёртку
возвращаемых значений в Promise.resolve или аналогичных
конструкциях.
Антипаттерн:
return Promise.resolve(fetch("/api/data"));
В большинстве случаев это избыточно, так как fetch уже
возвращает промис:
return fetch("/api/data");
Плагин ориентирован на упрощение цепочек и устранение лишнего уровня абстракции.
Некоторые конфигурации включают
promise/prefer-await-to-then, стимулирующее переход от
цепочек .then() к синтаксису async/await.
Пример нарушения:
function getData() {
return fetch("/api/data")
.then(res => res.json())
.then(data => data);
}
Рекомендуемая форма:
async function getData() {
const res = await fetch("/api/data");
const data = await res.json();
return data;
}
Цель правила — снижение когнитивной сложности асинхронного кода.
promise/no-new-statics контролирует некорректное
использование статических методов промисов в ситуациях, где они не
нужны.
Антипаттерн:
new Promise.resolve(value);
Правильно:
Promise.resolve(value);
Правило помогает избегать ошибок, связанных с неправильным использованием API Promise.
Плагин уделяет особое внимание обработке исключений внутри промисов. Основная проблема заключается в том, что исключения в асинхронных цепочках часто теряются.
Неправильный пример:
fetch("/api/data")
.then(response => {
JSON.parse(response.data);
});
Если JSON.parse выбрасывает ошибку, она может остаться
необработанной.
Корректный подход:
fetch("/api/data")
.then(response => {
try {
return JSON.parse(response.data);
} catch (e) {
return Promise.reject(e);
}
})
.catch(err => {
console.error(err);
});
Каждое правило может иметь один из уровней:
off — отключено;warn — предупреждение;error — ошибка сборки.Пример строгой конфигурации:
{
"plugins": ["promise"],
"rules": {
"promise/catch-or-return": "error",
"promise/always-return": "error",
"promise/no-nesting": "error",
"promise/no-return-wrap": "warn",
"promise/prefer-await-to-then": "warn"
}
}
Такой подход часто используется в production-средах, где критична стабильность асинхронного поведения.
Использование eslint-plugin-promise приводит к
структурным изменениям в кодовой базе:
Особенно заметен эффект в больших кодовых базах, где без контроля промисов быстро возникает хаос из «потерянных» ошибок и неполных цепочек.
Хотя плагин исторически ориентирован на .then() цепочки,
он также применяется к async/await. В этом случае он
проверяет:
try/catch;Пример некорректного кода:
async function load() {
fetch("/api/data");
}
Исправление:
async function load() {
const res = await fetch("/api/data");
return res;
}
или с обработкой ошибок:
async function load() {
try {
const res = await fetch("/api/data");
return res;
} catch (e) {
console.error(e);
throw e;
}
}