Асинхронное программирование представляет собой фундаментальную концепцию в JavaScript, которая позволяет выполнять длительные операции без блокировки основного потока выполнения программы. В современной веб-разработке асинхронность играет ключевую роль при работе с сетевыми запросами, операциями ввода-вывода и другими задачами, требующими ожидания результата.
В основе асинхронного выполнения лежит принцип неблокирующих операций. Когда JavaScript встречает асинхронную операцию, он не останавливает выполнение всей программы, а продолжает обрабатывать другие задачи, пока не будет получен результат асинхронной операции. Это особенно важно для создания отзывчивых веб-приложений, где пользовательский интерфейс должен оставаться активным даже во время выполнения сложных операций.
Рассмотрим простой пример асинхронной операции:
Javascript | 1
2
3
4
5
| console.log("Начало программы");
setTimeout(() => {
console.log("Это выполнится через 2 секунды");
}, 2000);
console.log("Конец программы"); |
|
В этом примере сообщения "Начало программы" и "Конец программы" выведутся немедленно, а сообщение внутри setTimeout появится только через 2 секунды. Это демонстрирует основной принцип асинхронности – программа не ждет завершения длительной операции, а продолжает выполнение дальше.
Однако работа с асинхронным кодом создает определенные сложности при получении и обработке результатов выполнения функций. Возврат значений из асинхронных операций требует специальных подходов, поскольку обычное использование оператора return не даст желаемого результата. Это связано с тем, что к моменту возврата значения асинхронная операция может быть еще не завершена.
Для решения этой проблемы в JavaScript существует несколько механизмов: callback-функции, промисы и async/await. Каждый из этих подходов имеет свои особенности и преимущества, которые мы подробно рассмотрим в следующих разделах. Правильное понимание этих механизмов критически важно для разработки эффективных и надежных веб-приложений.
Использование callbacks
Callback-функции являются одним из старейших и фундаментальных способов работы с асинхронными операциями в JavaScript. По своей сути, callback представляет собой функцию, которая передается в качестве аргумента другой функции и вызывается после завершения асинхронной операции. Этот механизм позволяет обрабатывать результаты асинхронных операций в момент их фактического получения.
Рассмотрим базовую структуру использования callback-функций на примере чтения файла:
Javascript | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| function readFileAsync(path, callback) {
// Имитация асинхронного чтения файла
setTimeout(() => {
const content = "Содержимое файла";
callback(null, content);
}, 1000);
}
readFileAsync("example.txt", (error, content) => {
if (error) {
console.error("Произошла ошибка:", error);
return;
}
console.log("Содержимое файла:", content);
}); |
|
В этом примере функция readFileAsync принимает два параметра: путь к файлу и callback-функцию. После завершения операции чтения файла, callback-функция вызывается с двумя аргументами: первый для передачи ошибки (если она возникла), второй для передачи результата операции. Такой паттерн обработки ошибок является стандартным для Node.js и широко используется в экосистеме JavaScript.
Обработка ошибок в callback-функциях требует особого внимания. Существует устоявшийся паттерн, когда первым параметром callback-функции всегда передается объект ошибки (или null, если ошибки нет), а вторым – результат успешного выполнения операции. Рассмотрим более сложный пример с обработкой ошибок:
Javascript | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| function fetchUserData(userId, callback) {
setTimeout(() => {
if (!userId) {
callback(new Error("ID пользователя не указан"));
return;
}
const userData = {
id: userId,
name: "John Doe",
email: "john@example.com"
};
callback(null, userData);
}, 1000);
}
fetchUserData(123, (error, userData) => {
if (error) {
console.error("Ошибка при получении данных:", error);
return;
}
processUserData(userData, (error, result) => {
if (error) {
console.error("Ошибка при обработке данных:", error);
return;
}
saveUserData(result, (error, success) => {
if (error) {
console.error("Ошибка при сохранении:", error);
return;
}
console.log("Данные успешно сохранены");
});
});
}); |
|
Этот пример демонстрирует одну из главных проблем использования callback-функций – образование так называемого "callback hell" (ада callback'ов), когда множество вложенных друг в друга callback-функций создают сложную для понимания и поддержки структуру кода. Каждый уровень вложенности добавляет новый контекст обработки ошибок и усложняет отслеживание потока выполнения программы.
Для улучшения читаемости кода при работе с callback-функциями рекомендуется выносить callback-функции в отдельные именованные функции:
Javascript | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| function handleError(error) {
console.error("Произошла ошибка:", error);
}
function processResult(result) {
console.log("Обработка результата:", result);
}
function performOperation(data, callback) {
setTimeout(() => {
const result = data * 2;
callback(null, result);
}, 1000);
}
performOperation(5, (error, result) => {
if (error) {
handleError(error);
return;
}
processResult(result);
}); |
|
Важным аспектом работы с callback-функциями является понимание механизма замыканий (closures), который позволяет callback-функциям сохранять доступ к переменным из внешней области видимости. Это особенно полезно при необходимости передачи дополнительных данных между асинхронными операциями:
Javascript | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| function createAsyncOperation(initialValue) {
let counter = initialValue;
return function executeOperation(callback) {
setTimeout(() => {
counter += 1;
callback(null, counter);
}, 1000);
};
}
const operation = createAsyncOperation(5);
operation((error, result) => {
console.log("Первый вызов:", result); // Выведет 6
operation((error, result) => {
console.log("Второй вызов:", result); // Выведет 7
});
}); |
|
Параллельное выполнение нескольких асинхронных операций с использованием callback-функций требует особого подхода. Один из распространенных паттернов – использование счетчика завершенных операций:
Javascript | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
| function parallelOperations(operations, finalCallback) {
const results = [];
let completed = 0;
operations.forEach((operation, index) => {
operation((error, result) => {
if (error) {
finalCallback(error);
return;
}
results[index] = result;
completed += 1;
if (completed === operations.length) {
finalCallback(null, results);
}
});
});
}
const asyncOperations = [
(cb) => setTimeout(() => cb(null, "Первый"), 1000),
(cb) => setTimeout(() => cb(null, "Второй"), 500),
(cb) => setTimeout(() => cb(null, "Третий"), 1500)
];
parallelOperations(asyncOperations, (error, results) => {
if (error) {
console.error("Произошла ошибка:", error);
return;
}
console.log("Все операции завершены:", results);
}); |
|
При работе с callback-функциями важно помнить о принципе единственной ответственности. Каждая callback-функция должна выполнять только одну конкретную задачу, что упрощает отладку и поддержку кода. Также следует избегать излишней вложенности callback-функций, используя модульный подход и декомпозицию сложных операций на более простые составляющие:
Javascript | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
| function validateInput(data, callback) {
setTimeout(() => {
if (!data.name || !data.email) {
callback(new Error("Неполные данные"));
return;
}
callback(null, data);
}, 300);
}
function processValidData(data, callback) {
setTimeout(() => {
const processed = {
...data,
email: data.email.toLowerCase(),
timestamp: Date.now()
};
callback(null, processed);
}, 500);
}
function saveToDatabase(data, callback) {
setTimeout(() => {
// Имитация сохранения в базу данных
const savedData = {
id: Math.random().toString(36).substr(2, 9),
...data
};
callback(null, savedData);
}, 700);
}
// Использование композиции функций
function handleUserData(userData) {
validateInput(userData, (error, validated) => {
if (error) {
console.error("Ошибка валидации:", error);
return;
}
processValidData(validated, (error, processed) => {
if (error) {
console.error("Ошибка обработки:", error);
return;
}
saveToDatabase(processed, (error, saved) => {
if (error) {
console.error("Ошибка сохранения:", error);
return;
}
console.log("Данные успешно сохранены:", saved);
});
});
});
} |
|
Результат колбэка вернуть как результат функции Добрый день, подскажите плииииз, такое в принципе возможно? (потери в продуктивности не важны)
Есть "линейная" функция (без колбэка)... Как вернуть результат из функции Привет. Делаю чат на socket.io, надо вывести последние 10 сообщений. Не знаю как чтото вернуть из функции, которую написал :)
var Tasks = { ... Ответ сервера вернуть, как результат функции Всем привет.
Не могу найти пример кода, на jQuery, который бы использовал $.ajax(), в теле функции, которая возвращала бы результатом ответ... Как вернуть результат функции в литерал объекта Всем здасьте, Пытаюсь написать скрипт рулетки. Ссылка на файлы
Затык в следующем - при нажатии на кнопку start запускается function updateNumber()....
Промисы (Promise)
Промисы представляют собой более современный и удобный способ работы с асинхронными операциями в JavaScript, который появился как решение проблем, связанных с использованием callback-функций. Промис – это объект, представляющий результат асинхронной операции, который может находиться в одном из трех состояний: ожидание (pending), выполнено (fulfilled) или отклонено (rejected).
Создание промиса осуществляется с помощью конструктора Promise, который принимает функцию-исполнитель (executor) с двумя параметрами: resolve и reject. Рассмотрим базовый пример создания промиса:
Javascript | 1
2
3
4
5
6
7
8
9
10
| const myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
const randomNumber = Math.random();
if (randomNumber > 0.5) {
resolve(`Успех! Число: ${randomNumber}`);
} else {
reject(`Ошибка! Число слишком маленькое: ${randomNumber}`);
}
}, 1000);
}); |
|
Цепочки промисов являются одним из главных преимуществ этого подхода. Метод then() возвращает новый промис, что позволяет создавать последовательности асинхронных операций без глубокой вложенности. Каждый then может трансформировать данные и передавать их дальше по цепочке:
Javascript | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
| function fetchUserProfile(userId) {
return new Promise((resolve, reject) => {
setTimeout(() => {
const user = {
id: userId,
name: "John Doe"
};
resolve(user);
}, 1000);
});
}
function fetchUserPosts(user) {
return new Promise((resolve, reject) => {
setTimeout(() => {
const posts = [
{ id: 1, title: "First Post", userId: user.id },
{ id: 2, title: "Second Post", userId: user.id }
];
resolve({ user, posts });
}, 1000);
});
}
fetchUserProfile(123)
.then(user => fetchUserPosts(user))
.then(data => {
console.log(`Получены посты пользователя ${data.user.name}:`, data.posts);
})
.catch(error => {
console.error("Произошла ошибка:", error);
}); |
|
Метод catch() используется для централизованной обработки ошибок в цепочке промисов. Он перехватывает любые ошибки, возникшие на предыдущих этапах. Это значительно упрощает обработку ошибок по сравнению с подходом callback-функций:
Javascript | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| function validateData(data) {
return new Promise((resolve, reject) => {
if (!data.email) {
reject(new Error("Email обязателен"));
return;
}
if (!data.password) {
reject(new Error("Пароль обязателен"));
return;
}
resolve(data);
});
}
validateData({ email: "user@example.com" })
.then(data => {
console.log("Данные валидны:", data);
})
.catch(error => {
console.error("Ошибка валидации:", error.message);
}); |
|
Параллельное выполнение нескольких промисов может быть организовано с помощью статических методов Promise.all(), Promise.race() и Promise.allSettled(). Promise.all() ожидает завершения всех промисов и возвращает массив их результатов:
Javascript | 1
2
3
4
5
6
7
8
9
10
11
| const promise1 = new Promise(resolve => setTimeout(() => resolve(1), 1000));
const promise2 = new Promise(resolve => setTimeout(() => resolve(2), 2000));
const promise3 = new Promise(resolve => setTimeout(() => resolve(3), 1500));
Promise.all([promise1, promise2, promise3])
.then(results => {
console.log("Все промисы завершены:", results);
})
.catch(error => {
console.error("Один из промисов завершился с ошибкой:", error);
}); |
|
Promise.race() возвращает результат первого завершившегося промиса, а Promise.allSettled() ожидает завершения всех промисов независимо от их статуса и возвращает массив с подробной информацией о результатах каждого промиса:
Javascript | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| const promises = [
new Promise((resolve, reject) => setTimeout(() => resolve("Success"), 1000)),
new Promise((resolve, reject) => setTimeout(() => reject("Error"), 500)),
new Promise((resolve, reject) => setTimeout(() => resolve("Another success"), 1500))
];
Promise.allSettled(promises)
.then(results => {
results.forEach((result, index) => {
if (result.status === "fulfilled") {
console.log(`Промис ${index + 1} успешно выполнен:`, result.value);
} else {
console.log(`Промис ${index + 1} завершился с ошибкой:`, result.reason);
}
});
}); |
|
Для упрощения работы с динамическими данными промисы поддерживают цепочки преобразований. Каждый then может не только получать результат предыдущей операции, но и трансформировать его для следующего обработчика:
Javascript | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| function getUserData(userId) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({ id: userId, name: "User Name" });
}, 1000);
})
.then(user => {
// Добавляем дополнительную информацию
user.role = "admin";
return user;
})
.then(user => {
// Форматируем данные
return {
...user,
createdAt: new Date().toISOString()
};
});
} |
|
Обработка множественных ошибок в промисах может быть организована с использованием нескольких catch-блоков для разных типов ошибок:
Javascript | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
| function processData(data) {
return new Promise((resolve, reject) => {
if (!data) {
reject(new ValidationError("Данные отсутствуют"));
}
resolve(data);
})
.then(processStep1)
.catch(error => {
if (error instanceof ValidationError) {
// Обработка ошибок валидации
console.error("Ошибка валидации:", error);
throw error;
}
// Пропускаем другие ошибки дальше
throw error;
})
.then(processStep2)
.catch(error => {
if (error instanceof ProcessingError) {
// Обработка ошибок обработки
console.error("Ошибка обработки:", error);
throw error;
}
// Пропускаем другие ошибки дальше
throw error;
});
} |
|
Промисификация - это процесс преобразования функций, использующих callback-подход, в функции, возвращающие промисы. Этот подход особенно полезен при работе с устаревшими API или библиотеками:
Javascript | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
| function promisify(fn) {
return function (...args) {
return new Promise((resolve, reject) => {
fn(...args, (error, result) => {
if (error) {
reject(error);
} else {
resolve(result);
}
});
});
};
}
// Пример использования
const originalFunction = (value, callback) => {
setTimeout(() => {
if (value < 0) {
callback(new Error("Значение должно быть положительным"));
} else {
callback(null, value * 2);
}
}, 1000);
};
const promisifiedFunction = promisify(originalFunction);
promisifiedFunction(10)
.then(result => console.log("Результат:", result))
.catch(error => console.error("Ошибка:", error)); |
|
Важным аспектом работы с промисами является понимание их микротаскового характера выполнения. Обработчики промисов выполняются в отдельной очереди микрозадач, что может влиять на порядок выполнения асинхронного кода:
Javascript | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| console.log("Начало");
Promise.resolve()
.then(() => console.log("Промис 1"))
.then(() => console.log("Промис 2"));
setTimeout(() => {
console.log("Таймер");
}, 0);
console.log("Конец");
// Вывод:
// Начало
// Конец
// Промис 1
// Промис 2
// Таймер |
|
Async/await
Async/await представляет собой современный синтаксический способ работы с промисами, который делает асинхронный код более читаемым и похожим на синхронный. Этот подход появился в ECMAScript 2017 и быстро стал предпочтительным методом обработки асинхронных операций благодаря своей простоте и выразительности.
Ключевым элементом этого подхода является ключевое слово async, которое используется для объявления асинхронной функции. Такая функция автоматически возвращает промис, а внутри неё можно использовать оператор await для ожидания результатов других асинхронных операций:
Javascript | 1
2
3
4
5
6
7
8
9
10
| async function fetchUserData(userId) {
try {
const response = await fetch(`/api/users/${userId}`);
const userData = await response.json();
return userData;
} catch (error) {
console.error("Ошибка при получении данных пользователя:", error);
throw error;
}
} |
|
В этом примере код выглядит почти как синхронный, но при этом не блокирует выполнение программы. Оператор await приостанавливает выполнение асинхронной функции до получения результата промиса, что делает код более понятным и устраняет необходимость использования цепочек then.
Обработка исключений в async/await осуществляется с помощью стандартных конструкций try/catch, что значительно упрощает работу с ошибками по сравнению с цепочками промисов:
Javascript | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| async function processUserData() {
try {
const user = await fetchUserProfile();
const posts = await fetchUserPosts(user.id);
const comments = await fetchPostComments(posts);
return {
user,
posts,
comments
};
} catch (error) {
if (error instanceof NetworkError) {
console.error("Ошибка сети:", error);
// Повторная попытка или альтернативная логика
} else if (error instanceof ValidationError) {
console.error("Ошибка валидации:", error);
// Обработка ошибок валидации
} else {
console.error("Неизвестная ошибка:", error);
// Общая обработка ошибок
}
throw error;
}
} |
|
При работе с несколькими асинхронными операциями async/await можно комбинировать с методами Promise.all() или Promise.race() для организации параллельного выполнения:
Javascript | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| async function loadAllData() {
try {
const [userData, settings, notifications] = await Promise.all([
fetchUserData(),
fetchUserSettings(),
fetchUserNotifications()
]);
return {
user: userData,
settings: settings,
notifications: notifications
};
} catch (error) {
console.error("Ошибка при загрузке данных:", error);
throw error;
}
} |
|
Важной особенностью async/await является возможность использования циклов для последовательной обработки асинхронных операций, что было бы значительно сложнее реализовать с помощью обычных промисов:
Javascript | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| async function processItems(items) {
const results = [];
for (const item of items) {
try {
const processedItem = await processItem(item);
const validatedItem = await validateItem(processedItem);
const savedItem = await saveItem(validatedItem);
results.push(savedItem);
} catch (error) {
console.error(`Ошибка обработки элемента ${item.id}:`, error);
// Продолжаем обработку следующих элементов
continue;
}
}
return results;
} |
|
Этот подход особенно полезен, когда необходимо обработать массив элементов последовательно, с возможностью обработки ошибок для каждого элемента отдельно. При этом важно помнить, что для параллельной обработки массива элементов лучше использовать Promise.all() в сочетании с методом map:
Javascript | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| async function processItemsParallel(items) {
const processPromises = items.map(async item => {
try {
const processed = await processItem(item);
const validated = await validateItem(processed);
return await saveItem(validated);
} catch (error) {
console.error(`Ошибка обработки элемента ${item.id}:`, error);
return null;
}
});
const results = await Promise.all(processPromises);
return results.filter(result => result !== null);
} |
|
При создании асинхронных функций с помощью async/await важно учитывать контекст выполнения и возможность использования стрелочных функций. Стрелочные функции особенно удобны при работе с классами и объектами:
Javascript | 1
2
3
4
5
6
7
8
9
10
| class DataService {
constructor(apiUrl) {
this.apiUrl = apiUrl;
}
fetchData = async () => {
const response = await fetch(this.apiUrl);
return response.json();
}
} |
|
Одним из преимуществ async/await является возможность создания более сложных потоков управления с условной логикой. Это позволяет реализовывать комплексные алгоритмы обработки данных:
Javascript | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| async function processDataWithRetry(data, maxAttempts = 3) {
let attempts = 0;
while (attempts < maxAttempts) {
try {
const result = await sendData(data);
if (result.status === 'pending') {
await new Promise(resolve => setTimeout(resolve, 1000));
attempts++;
continue;
}
return result;
} catch (error) {
attempts++;
if (attempts === maxAttempts) {
throw new Error('Превышено максимальное количество попыток');
}
await new Promise(resolve => setTimeout(resolve, 1000 * attempts));
}
}
} |
|
Асинхронные генераторы представляют собой мощную комбинацию async/await и итераторов, позволяющую создавать потоки асинхронных данных:
Javascript | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| async function* createDataStream() {
let page = 1;
while (true) {
const response = await fetch(`/api/data?page=${page}`);
const data = await response.json();
if (data.length === 0) {
return;
}
yield* data;
page++;
}
}
async function processDataStream() {
for await (const item of createDataStream()) {
await processItem(item);
}
} |
|
При работе с async/await важно помнить о правильном структурировании кода и избегании антипаттернов. Например, не следует создавать ненужные асинхронные функции или использовать await там, где это не требуется:
Javascript | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| // Неправильно
async function getData() {
return await Promise.resolve(42); // Излишнее использование await
}
// Правильно
async function getData() {
return Promise.resolve(42);
}
// Неправильно
const processArray = async (items) => {
const results = [];
for (const item of items) {
results.push(await processItem(item)); // Последовательное выполнение
}
return results;
}
// Правильно
const processArray = async (items) => {
return Promise.all(items.map(item => processItem(item))); // Параллельное выполнение
} |
|
Еще одним важным аспектом является обработка отмены асинхронных операций. Для этого можно использовать AbortController:
Javascript | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| async function fetchWithTimeout(url, timeoutMs) {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), timeoutMs);
try {
const response = await fetch(url, {
signal: controller.signal
});
clearTimeout(timeout);
return await response.json();
} catch (error) {
if (error.name === 'AbortError') {
throw new Error('Запрос отменен по таймауту');
}
throw error;
}
} |
|
Практические рекомендации
При работе с асинхронными операциями в JavaScript важно следовать определенным принципам и рекомендациям, которые помогут создавать более надежный и поддерживаемый код. Выбор оптимального подхода зависит от конкретной ситуации и требований проекта. Для новых проектов рекомендуется использовать async/await как наиболее современный и читаемый способ работы с асинхронным кодом. Однако в некоторых случаях, особенно при обработке событий или создании библиотек, использование промисов или даже callback-функций может быть более уместным.
При работе с асинхронным кодом следует избегать распространенных ошибок. Одна из типичных ошибок – игнорирование обработки исключений. Каждая асинхронная операция должна включать механизм обработки ошибок, будь то блок catch при использовании async/await или метод catch() в цепочке промисов. Также важно помнить о возможности возникновения состояния гонки (race condition) при параллельном выполнении нескольких асинхронных операций и принимать соответствующие меры для его предотвращения.
Для оптимизации производительности рекомендуется использовать параллельное выполнение независимых асинхронных операций с помощью Promise.all(). Однако следует быть осторожным с количеством одновременно выполняемых операций, особенно если они связаны с сетевыми запросами. В таких случаях может быть полезно реализовать механизм ограничения количества параллельных запросов или использовать очередь для их последовательной обработки.
Javascript | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| async function optimizedDataFetch(urls, concurrencyLimit = 3) {
const results = [];
const queue = [...urls];
const inProgress = new Set();
while (queue.length > 0 || inProgress.size > 0) {
while (inProgress.size < concurrencyLimit && queue.length > 0) {
const url = queue.shift();
const promise = fetch(url)
.then(response => response.json())
.finally(() => inProgress.delete(promise));
inProgress.add(promise);
results.push(promise);
}
await Promise.race(inProgress);
}
return Promise.all(results);
} |
|
Этот подход позволяет эффективно управлять ресурсами и предотвращать перегрузку системы при обработке большого количества асинхронных операций. При разработке асинхронного кода также важно учитывать возможность отмены операций и освобождения ресурсов, особенно в веб-приложениях, где пользователь может покинуть страницу до завершения всех запросов.
Вернуть результат выполнения функции Добрый день уважаемые форумчане. Имеются две функции.
<button id="btn">Click me</button>
<div id="result"></div> ... Вернуть результат из функции на основании параметра возможно, холивар - но рили в недоумении
getIcon(source) {
if(source == undefined) return 'doctype:folder';
let result;
... Как дождаться выполнения асинхронной функции? Привет, Есть проэкт Node.js+angular+typescript. И у меня есть функция:
window.speechSynthesis.speak(new SpeechSynthesisUtterance("Hello, my... Как вернуть результат без перезагрузки Как вернуть моментально результат в виде диалога,
к примеру если написать "Hello", этот сообщение сразу обновит и в других пользователей. Получить значение из асинхронной функции Здравствуйте. Помогите мне пожалуйста. Нужно вернуть с помощью return значение глобальной переменной b. Но у меня return возвращает undefined так как... JavaScript!? Как вернуть порядковый номер выбранного(чекнутого) элемента radio button!? вопрос собственно в заголовке.
ну напр. есть форма с 4-мя radio button, я выбираю(чекаю) например 2-ую и нажимаю ОК,
вот в переменную нужно... Обработка ошибок для асинхронной функции Здравствуйте.
Нашел код в инете.
В try/catch нет await - так разве должно работать?
async function myFunction {
// ...
await... Непонятное поведение асинхронной функции и fetch есть 2 варианта получения данных с колбеком и без, код ниже, оба запроса на токен работают, в нетворк код 200 и нужные данные, логи внутри функций... Как с JavaScript переместить в переменные результат SQL-запроса? Срочно нужна помощь!
Как с JavaScript переместить в переменные результат SQL-запроса?
SQL-запрос из rpc-Функции rpc.getData.js :
var... Как передать результат запроса ajax в переменную javascript? Есть функция, мне нужно получить значение переменной end в этой функции
function(data) {
//alert(data);
end = data;
} чтоб использовать... Ajax. Как в переменную JavaScript записать результат вычислений на сервере Аяксом нужно передать на сервер число. На сервере в php проводятся вычисления. Как результат этих вычислений получить в переменную javascript.... Как вернуть значение из функции Как записать выполнение таких конструкций в переменную?
let res = '';
connection.query("SELECT * FROM help_category",
...
|