← Назад к вопросам

Какое значение вернет асинхронная функция без return?

1.2 Junior🔥 201 комментариев
#Node.js и JavaScript

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Какое значение вернет асинхронная функция без return?

Ответ: Promise, который resolve-ится в undefined.

Это один из базовых, но часто неправильно понимаемых аспектов async/await в JavaScript. Разберу детально с примерами.

Базовый пример

// Функция без return
async function doSomething() {
  console.log('Doing something...');
  // нет return
}

// Что вернется?
const result = doSomething();
console.log(result); // Promise { <pending> }

// Когда Promise resolve-ится
result.then(value => {
  console.log('Resolved with:', value); // Resolved with: undefined
});

// Или с await
const value = await doSomething();
console.log(value); // undefined

Почему это происходит?

// Эти две функции эквивалентны:

// 1. async функция
async function getUser() {
  // код
  // нет return
}

// 2. обычная функция с Promise
function getUser() {
  return Promise.resolve(undefined);
}

// Обе возвращают Promise, который resolve-ится в undefined

Детальное объяснение

Когда ты объявляешь функцию как async:

async function example() {
  // что-то делаем
}

JavaScript автоматически оборачивает возвращаемое значение в Promise:

async function example() {
  return 'hello';
}
// Эквивалентно:
function example() {
  return Promise.resolve('hello');
}

// ─────────────────────────────────

async function example() {
  // нет return
}
// Эквивалентно:
function example() {
  return Promise.resolve(undefined);
}

// ─────────────────────────────────

async function example() {
  throw new Error('Oops');
}
// Эквивалентно:
function example() {
  return Promise.reject(new Error('Oops'));
}

Практические примеры

Пример 1: Функция без return (обработчик)

// Event listener, который ничего не возвращает
async function handleUserClick() {
  console.log('User clicked');
  await saveToDatabase();
  // нет return
}

const promise = handleUserClick();
console.log(promise); // Promise { <pending> }

promise.then(() => {
  console.log('Click handler completed'); // без значения
});

Пример 2: Функция с return

async function getUserById(id) {
  const user = await db.users.findOne({ id });
  return user; // явный return
}

const promise = getUserById(123);
// promise разрешится в объект user

promise.then(user => {
  console.log(user); // { id: 123, name: 'John' }
});

Пример 3: Частая ошибка

// ❌ Неправильно: забыли return
async function getUserEmail(userId) {
  const user = await db.users.findOne({ id: userId });
  user.email; // это выражение, но не return!
}

const email = await getUserEmail(123);
console.log(email); // undefined ← Неожиданно!

// ✅ Правильно: добавляем return
async function getUserEmail(userId) {
  const user = await db.users.findOne({ id: userId });
  return user.email; // явный return
}

const email = await getUserEmail(123);
console.log(email); // 'user@example.com'

Применение в Node.js backend

// Express middleware: часто не возвращает значение
app.post('/users', async (req, res) => {
  const user = new User(req.body);
  await user.save();
  res.json(user);
  // нет return - и это нормально! (возвращается undefined)
});

// Service функция: возвращает значение
class UserService {
  async getUserById(id: string) {
    const user = await User.findById(id);
    return user; // ← важно вернуть
  }

  async deleteUser(id: string) {
    await User.deleteOne({ _id: id });
    // нет return - функция resolve-ится в undefined
    // это нормально для операций "side-effects"
  }
}

// Использование
const user = await userService.getUserById(123);
console.log(user); // User объект

const result = await userService.deleteUser(123);
console.log(result); // undefined - и это ожидаемо

Важная разница: await без return

// ❌ Неправильно: await но без return
async function getUserName(userId) {
  const user = await db.findUser(userId);
  user.name; // это значение теряется!
}

const name = await getUserName(123);
console.log(name); // undefined

// ✅ Правильно: return после await
async function getUserName(userId) {
  const user = await db.findUser(userId);
  return user.name;
}

const name = await getUserName(123);
console.log(name); // 'John'

Обработка undefined в async функциях

// Когда нельзя избежать undefined, нужно обработать
async function processUser(userId) {
  const user = await getUser(userId);
  if (!user) {
    throw new Error('User not found'); // явная ошибка
  }
  return user; // гарантированно не undefined
}

// Или использовать null coalescing
async function getDefaultUser(userId) {
  const user = await getUser(userId);
  return user ?? { id: null, name: 'Anonymous' };
}

Цепочка async функций

// Если первая функция возвращает undefined
async function step1() {
  // нет return
}

async function step2(value) {
  console.log(value); // undefined
  return 'result';
}

async function main() {
  const result1 = await step1();
  const result2 = await step2(result1); // передаем undefined!
  
  return result2; // 'result'
}

main().then(r => console.log(r)); // 'result'

Best Practices

1. Всегда явно return значение, если оно нужно

// ❌ Неправильно
async function fetchUser(id) {
  const user = await db.query('SELECT * FROM users WHERE id = $1', [id]);
  user; // потеряется
}

// ✅ Правильно
async function fetchUser(id) {
  const user = await db.query('SELECT * FROM users WHERE id = $1', [id]);
  return user;
}

2. Если ничего не возвращаешь, сделай это явным

// ✅ Хорошо: явная типизация что ничего не возвращается
async function logUserAction(userId, action): Promise<void> {
  await auditLog.save({ userId, action });
  // нет return - ожидается undefined
}

// Использование:
await logUserAction(123, 'login'); // ничего не ждем

3. Использование void для явности

// TypeScript
async function doSideEffect(): Promise<void> {
  await something();
  // Promise<void> = undefined будет возвращен
}

// Попытка использовать возвращаемое значение:
const x = await doSideEffect(); // TypeScript ошибка

4. Хорошее практика: типизируй возвращаемые значения

// ✅ Явная типизация
async function getUser(id: string): Promise<User> {
  return await db.findUser(id);
}

async function deleteUser(id: string): Promise<void> {
  await db.deleteUser(id);
}

async function updateUser(user: User): Promise<User> {
  return await db.updateUser(user);
}

Частые ошибки

Ошибка 1: забыть return в if

async function getStatus(userId) {
  const user = await db.getUser(userId);
  
  if (user.isPremium) {
    'premium'; // ❌ теряется
  }
  
  return 'free'; // вернется 'free' даже для premium
}

// Исправление:
async function getStatus(userId) {
  const user = await db.getUser(userId);
  
  if (user.isPremium) {
    return 'premium'; // ✅ явный return
  }
  
  return 'free';
}

Ошибка 2: забыть return в map

// ❌ Неправильно
const promises = users.map(async (user) => {
  await processUser(user);
  // нет return
});

await Promise.all(promises); // Все resolve в undefined

// ✅ Правильно
const promises = users.map(async (user) => {
  return await processUser(user); // явный return
});

const results = await Promise.all(promises); // результаты

Итог

  • Async функция ВСЕГДА возвращает Promise
  • Если нет явного return, Promise resolve-ится в undefined
  • Это не ошибка, но часто признак забытого return
  • Используй TypeScript для проверки типов: Promise<void> если ничего не возвращается
  • Явное лучше чем неявное: всегда пиши return или аннотируй Promise<void>

На собеседовании этот вопрос часто задают, чтобы проверить понимание async/await. Правильный ответ показывает, что ты понимаешь, что async функция это синтаксический сахар над Promise.