В коде на JavaScript для одностраничного приложения используется setTimeout для ожидания завершения AJAX‑запроса: покажите типичную ошибку синхронизации, объясните, почему она возникает, и опишите, как правильно организовать асинхронную логику с промисами или async/await

18 Ноя в 17:29
3 +1
0
Ответы
1
Типичная ошибка
- Разработчик ставит фиксированную задержку через setTimeout и надеется, что AJAX‑запрос успеет завершиться, например: запрос идёт, затем через 100010001000 мс читают результат — иногда работает, иногда нет.
Пример неправильного кода
```javascript
let data;
fetch('/api/data')
.then(r => r.json())
.then(d => { data = d; });
// Надеемся, что через 1000 мс data уже заполнен
setTimeout(() => {
console.log(data.length); // может быть undefined или бросить ошибку
}, 1000);
```
Почему это ошибка
- Время отклика сервера и сеть непредсказуемы: ответ может прийти быстрее или медленнее заданной задержки.
- Такой код создаёт гонку (race condition): чтение происходит независимо от фактического завершения асинхронной операции.
- setTimeout не "ждёт" завершения запроса — он просто откладывает выполнение на фиксированное время.
Как правильно: промисы (.then) или async/await
1) С промисами (.then)
- Привязывайте последующие действия к разрешению промиса, а не к таймеру.
```javascript
fetch('/api/data')
.then(response => {
if (!response.ok) throw new Error(response.statusText);
return response.json();
})
.then(data => {
console.log(data.length); // выполняется только после получения данных
})
.catch(err => {
console.error('Ошибка запроса:', err);
});
```
2) С async/await (более декларативно)
```javascript
async function loadData() {
try {
const response = await fetch('/api/data');
if (!response.ok) throw new Error(response.statusText);
const data = await response.json();
console.log(data.length);
} catch (err) {
console.error('Ошибка запроса:', err);
}
}
loadData();
```
Дополнительно (полезные практики)
- Если нужно одновременно ждать нескольких запросов — используйте \`Promise.all\`:
```javascript
const [a, b] = await Promise.all([fetch('/a').then(r => r.json()), fetch('/b').then(r => r.json())]);
```
- Для отмены запроса используйте AbortController:
```javascript
const ac = new AbortController();
fetch('/api/data', { signal: ac.signal }).then(...).catch(err => {
if (err.name === 'AbortError') console.log('Запрос отменён');
});
ac.abort(); // отмена
```
Кратко: не заменяйте синхронизацию таймером. Привязывайте код к завершению промиса (.then / await), обрабатывайте ошибки и используйте AbortController или Promise.all при необходимости.
18 Ноя в 18:16
Не можешь разобраться в этой теме?
Обратись за помощью к экспертам
Гарантированные бесплатные доработки в течение 1 года
Быстрое выполнение от 2 часов
Проверка работы на плагиат
Поможем написать учебную работу
Прямой эфир