В JavaScript-фрагменте: promises = urls.map(u=>fetch(u).then(r=>r.text()).then(t=>console.log(t))); — вывод получается в непредсказуемом порядке, нужно обработать последовательные запросы и в случае ошибки продолжить — перепишите с async/await и объясните различия в управлении потоком
Код (последовательно, с продолжением при ошибке — каждая ошибка ловится и логируется, цикл продолжается): ```javascript async function processUrlsSequential(urls) { for (const url of urls) { try { const res = await fetch(url); if (!res.ok) throw new Error(`HTTP ${res.status} ${res.statusText}`); const text = await res.text(); console.log(text); } catch (err) { console.error('Error fetching', url, err); // можно продолжить или сохранять информацию об ошибке } } } // Вызов: processUrlsSequential(urls); ``` Ключевые отличия в управлении потоком: - Оригинал `urls.map(u => fetch(u).then(...))` стартует все запросы параллельно — результат `console.log` будет в порядке завершения (не предсказуемом). - `async/await` делает код «похожим на синхронный»: `await` приостанавливает выполнение текущей async-функции до результата промиса, поэтому в `for...of` запросы выполняются последовательно (следующий стартует только после завершения предыдущего). - Ошибки: с `then` их обрабатывают через `.catch`, но с `await` удобнее использовать `try/catch` — можно ловить каждую итерацию отдельно и продолжать цикл. - `await` не блокирует Event Loop глобально — блокируется только выполнение текущей async-функции; другие задачи в приложении продолжают работать. Примечание: `fetch` не отвергает промис при HTTP-статусе ошибки, поэтому полезно явно проверять `res.ok` (как в примере), если вы хотите считать 4xx/5xx ошибками.
```javascript
async function processUrlsSequential(urls) {
for (const url of urls) {
try {
const res = await fetch(url);
if (!res.ok) throw new Error(`HTTP ${res.status} ${res.statusText}`);
const text = await res.text();
console.log(text);
} catch (err) {
console.error('Error fetching', url, err);
// можно продолжить или сохранять информацию об ошибке
}
}
}
// Вызов:
processUrlsSequential(urls);
```
Ключевые отличия в управлении потоком:
- Оригинал `urls.map(u => fetch(u).then(...))` стартует все запросы параллельно — результат `console.log` будет в порядке завершения (не предсказуемом).
- `async/await` делает код «похожим на синхронный»: `await` приостанавливает выполнение текущей async-функции до результата промиса, поэтому в `for...of` запросы выполняются последовательно (следующий стартует только после завершения предыдущего).
- Ошибки: с `then` их обрабатывают через `.catch`, но с `await` удобнее использовать `try/catch` — можно ловить каждую итерацию отдельно и продолжать цикл.
- `await` не блокирует Event Loop глобально — блокируется только выполнение текущей async-функции; другие задачи в приложении продолжают работать.
Примечание: `fetch` не отвергает промис при HTTP-статусе ошибки, поэтому полезно явно проверять `res.ok` (как в примере), если вы хотите считать 4xx/5xx ошибками.