Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как заблокировать выполнение кода?
Этот вопрос можно интерпретировать по-разному: заблокировать выполнение асинхронного кода, остановить цикл, отменить операцию или контролировать выполнение. Рассмотрим все основные подходы.
Способ 1: Async/Await — ожидание перед продолжением
Самый простой способ "заблокировать" код — дождаться асинхронной операции:
// Без блокировки — код продолжает выполняться
fetch('/api/data');
console.log('Request sent'); // Выполнится сразу
// С блокировкой — ждем результата
await fetch('/api/data');
console.log('Data received'); // Выполнится только после ответа
Практический пример:
async function processUser() {
// Блокируем выполнение до загрузки пользователя
const response = await fetch('/api/user/123');
const user = await response.json();
// Код здесь выполнится только после получения данных
console.log('User:', user);
return user;
}
Способ 2: Promise.all() для ожидания нескольких операций
// Блокируем до завершения всех операций
const [users, posts, comments] = await Promise.all([
fetch('/api/users').then(r => r.json()),
fetch('/api/posts').then(r => r.json()),
fetch('/api/comments').then(r => r.json())
]);
// Код выполнится только когда все три запроса завершены
console.log('All data loaded');
Способ 3: AbortController — отменить операцию
AbortController позволяет отменить асинхронную операцию:
const controller = new AbortController();
// Отправляем запрос с сигналом отмены
const fetchPromise = fetch('/api/data', {
signal: controller.signal
});
// Отменяем запрос через 5 секунд
setTimeout(() => controller.abort(), 5000);
try {
const response = await fetchPromise;
const data = await response.json();
console.log('Data:', data);
} catch (error) {
if (error.name === 'AbortError') {
console.log('Request was cancelled');
} else {
console.error('Error:', error);
}
}
Практический пример: отмена при удалении компонента (React):
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
const controllerRef = useRef(null);
useEffect(() => {
// Создаем AbortController для этого запроса
const controller = new AbortController();
controllerRef.current = controller;
const fetchUser = async () => {
try {
const response = await fetch(`/api/users/${userId}`, {
signal: controller.signal
});
const data = await response.json();
setUser(data);
} catch (error) {
if (error.name !== 'AbortError') {
console.error('Error:', error);
}
}
};
fetchUser();
// При удалении компонента отменяем запрос
return () => controller.abort();
}, [userId]);
return user ? <div>{user.name}</div> : <div>Loading...</div>;
}
Способ 4: Condition flags — контролируемое выполнение
let shouldContinue = true;
async function longRunningTask() {
for (let i = 0; i < 1000000; i++) {
if (!shouldContinue) {
console.log('Task cancelled');
break; // Выход из цикла
}
// Heavy computation
doHeavyWork(i);
}
}
// Запустить задачу
longRunningTask();
// Остановить, когда нужно
shouldContinue = false;
Способ 5: Semaphore / Mutex — синхронизация доступа
Блокировка для ограничения одновременного доступа:
class Semaphore {
constructor(maxConcurrent = 1) {
this.maxConcurrent = maxConcurrent;
this.current = 0;
this.queue = [];
}
async acquire() {
if (this.current < this.maxConcurrent) {
this.current++;
return;
}
// Ждем, пока кто-то освободит место
return new Promise(resolve => {
this.queue.push(resolve);
});
}
release() {
this.current--;
const resolve = this.queue.shift();
if (resolve) {
this.current++;
resolve();
}
}
}
// Использование: максимум 2 одновременных запроса
const semaphore = new Semaphore(2);
async function fetchWithLimit(url) {
await semaphore.acquire();
try {
const response = await fetch(url);
return response.json();
} finally {
semaphore.release();
}
}
// Запускаем 5 запросов, но только 2 будут одновременно
Promise.all([
fetchWithLimit('/api/1'),
fetchWithLimit('/api/2'),
fetchWithLimit('/api/3'),
fetchWithLimit('/api/4'),
fetchWithLimit('/api/5')
]);
Способ 6: Busy waiting (не рекомендуется!)
// ❌ ПЛОХО — заморозит UI
function blockMainThread() {
const end = Date.now() + 5000;
while (Date.now() < end) {
// Активно занимаем процессор
}
console.log('Done');
}
// ✅ ХОРОШО — используй setTimeout
function blockMainThreadCorrectly() {
return new Promise(resolve => {
setTimeout(() => {
console.log('Done');
resolve();
}, 5000);
});
}
Способ 7: Generator функции для контролируемого выполнения
function* generatorTask() {
console.log('Step 1');
yield; // Пауза
console.log('Step 2');
yield; // Пауза
console.log('Step 3');
yield; // Пауза
console.log('Done');
}
const gen = generatorTask();
gen.next(); // Step 1
gen.next(); // Step 2
gen.next(); // Step 3
gen.next(); // Done
// Или с циклом:
for (const _ of generatorTask()) {
// Выполняется пошагово
}
Способ 8: Lock (с использованием Web Locks API)
// Современный способ заблокировать ресурс
navigator.locks.request('myResource', async lock => {
console.log('Lock acquired');
// Этот код выполняется с исключительным доступом
await doSomething();
console.log('Lock released');
}); // Блокировка автоматически освобождается
Практический пример: Rate Limiting
class RateLimiter {
constructor(maxRequests, windowMs) {
this.maxRequests = maxRequests;
this.windowMs = windowMs;
this.requests = [];
}
async acquire() {
const now = Date.now();
// Удаляем старые запросы (старше окна)
this.requests = this.requests.filter(
timestamp => now - timestamp < this.windowMs
);
// Если достигли лимита, ждем
if (this.requests.length >= this.maxRequests) {
const oldestRequest = this.requests[0];
const waitTime = this.windowMs - (now - oldestRequest);
console.log(`Rate limit exceeded. Waiting ${waitTime}ms`);
await new Promise(resolve => setTimeout(resolve, waitTime));
return this.acquire(); // Повторная попытка
}
// Добавляем текущий запрос
this.requests.push(now);
}
}
// Использование: максимум 5 запросов в 10 секунд
const limiter = new RateLimiter(5, 10000);
async function fetchWithRateLimit(url) {
await limiter.acquire();
return fetch(url);
}
// Запускаем 10 запросов, но выполнится в 2 батча
for (let i = 0; i < 10; i++) {
fetchWithRateLimit(`/api/${i}`);
}
Способ 9: Condition variables (для сложной синхронизации)
class ConditionVariable {
constructor() {
this.waiters = [];
}
async wait() {
return new Promise(resolve => {
this.waiters.push(resolve);
});
}
notify() {
const resolve = this.waiters.shift();
if (resolve) resolve();
}
notifyAll() {
while (this.waiters.length > 0) {
this.notify();
}
}
}
// Пример: Producer-Consumer
const queue = [];
const condition = new ConditionVariable();
const MAX_SIZE = 5;
async function producer(item) {
while (queue.length >= MAX_SIZE) {
console.log('Queue full, waiting...');
await condition.wait();
}
queue.push(item);
console.log('Produced:', item);
}
async function consumer() {
while (queue.length === 0) {
console.log('Queue empty, waiting...');
await condition.wait();
}
const item = queue.shift();
console.log('Consumed:', item);
condition.notifyAll(); // Разбудить producer'ов
}
Способ 10: setTimeout для отложенного выполнения
// Блокируем на 5 секунд
setTimeout(() => {
console.log('Executed after 5 seconds');
}, 5000);
// С Promise
await new Promise(resolve => setTimeout(resolve, 5000));
console.log('Done blocking');
Сравнение подходов
// 1. await (асинхронное ожидание) — рекомендуется
await asyncOperation();
// 2. AbortController (отмена операции) — для длительных задач
const controller = new AbortController();
await fetch(url, { signal: controller.signal });
// 3. Promise.all() — ожидание нескольких операций
await Promise.all([op1, op2, op3]);
// 4. Flag + условия — контролируемое выполнение
if (shouldContinue) { /* ... */ }
// 5. Semaphore — ограничение одновременного доступа
await semaphore.acquire();
// 6. setTimeout — отложенное выполнение
await new Promise(r => setTimeout(r, ms));
Заключение
Как заблокировать код в JavaScript:
- await — дождись асинхронной операции
- Promise.all() — жди несколько операций
- AbortController — отмени длительную операцию
- Flag + условия — контролируемое выполнение
- Semaphore/Mutex — синхронизация доступа
Важно помнить:
- Не блокируй main thread (UI зависнет)
- Используй асинхронный код (async/await)
- Отменяй ненужные операции (AbortController)
- Предоставляй feedback пользователю (loading state)