
Минимум об асинхронности
Асинхронный код в отличие от синхронного позволяет выполнять длительные операции продолжая работать приложению, не зависая когда идет обращение к серверу с фронтенда или когда идет выборка данных на сервере из базы данных.
Что же позволяет коду так работать?. Когда я 2022 г. увлекся разработкой на React (это JavaScript библиотека) и начал разрабатывать сайт с тестовыми погодными данными используя OpenWeatherMap, первое с чем столкнулся по теме о которой я сегодня пишу это конечно же promise.
Promise
В переводе с английского это обещать, при использование этого выражения какая-то функция обещает вернуть нам результат после завершения асинхронного выполнения, результатом могут быть как данные так и ошибка. В примерах которые я смотрел по использованию такого функционала, везде встречалась это слово promise. Я неслучайно обращаю ваше внимание на это, так как сейчас это необязательно, да и скажем не нужно использовать в коде за исключением Promise.All() об этой функции я расскажу чуть позже, сейчас покажу как было и как пишу код сейчас.
Backend как было
Ниже приведен код получения из таблицы "tableweather" базы данных на PostgresSQL c помощью асинхронной функции "getWeather" обернутой в Promise.
const getWeather = async (req, res) => {
return new Promise(function (resolve, reject) {
pool_weather.query(`SELECT * FROM tableweather`, (error, results) => {
if (error) {
reject(error);
}
resolve(results.rows);
});
});
};
У Promise есть resolve, результат успешного получения данных и reject который возвращает сообщение об ошибочном завершение операции это так называемые колбэки. Result ("Результат") -- вначале undefined, далее изменяется на value при вызове resolve(value) или на error при вызове reject(error). Наверно у кого то появится вопрос а причем здесь ''Backend" ? На нем запускается сервер и выполняются серверные процедуры в частности связанные с получением данных из базы данных Postgres которую я использую в своих проектах.
Ответ также в коде ниже рис2. Функцию "getWeather" вызывает серверная функция ""/api/getAllWeather" расположенная в файле server.js рис3. Где используется самый распространённый сервер - Express.
app.get(`/api/getAllWeather`, cors(corsOptions), (req, res) => {
console.log("Weather in all - city");
request.getWeather()
.then((response) => {
res.status(200).send(response);
})
.catch((error) => {
res.status(500).send(error);
});
});
рис 2.
На рис 3. Пример как выглядит мой проект разработанный с использованием библиотеке React для создания динамических веб-приложений.

рис3.
Backend как использовать сейчас
Вызов с фронтенда для получения данных о населенных пунктах обращается к app.get(/api/getCity
, cors(corsOptions), (req, res) => { } из файла server.js, и она в свою очередь активирует функции getCityList(), рис1. рис2.
app.get(`/api/getCity`, cors(corsOptions), (req, res) => {
console.log("You in Get - city");
request.getCityList()
.then((response) => {
res.status(200).send(response);
})
.catch((error) => {
res.status(500).send(error);
});
});
рис 1.
const getCityList = async (req, res) => {
try {
const response = await pool_weather.query(`SELECT * FROM tablecity`);
console.log("Получили в getCityList!!" + response.rows.length);
return response;
} catch (error) {
console.log("что то пошло не так в getCityList!!" + err.stack);
return res.status(500).send(error);
}
};
рис 2.
Из кода видно что нет - "return new Promise(function (resolve, reject)" и соответственно "resolve(results.rows)", и все потому что у асинхронной функции getCityList() имеющей директиву async, есть Promise обещание вернуть результат! Но для получения ответа нам не нужен Resolve, а нужен await (ждать) без которого асинхронная функция не работает. В итоге сразу получаем результат response или ошибку.
Читабельность кода более удобна особенно когда используются параллельное выполнение асинхронных функции (Promise.All) или цепочки промисов (blockchain), как их использовать я расскажу в следующем разделе, заодно и рассмотрим использование нового подхода работы с Promise на Frontend.
Цепочка промисов в асинхронной операции
Рассмотрим теперь как работает цепочка промисов ("blockchain), для этого в проекте реализованы функции как на клиенте так и на сервере, запускать выполнение будем при нажатии кнопки " Test Promice blockChain operathion!" рис 1. ,рис 2. , рис 3.

рис 1.

рис 2.

рис 3.
Ставим задачу получить из таблицы базы данных Postgres "tablecity" получить по наименованию реквизит "cityname", значение реквизита "cityid" а затем используя его как параметр из таблицы "tableweather" получить данные в которой они привязаны к населенным пунктам через реквизит "cityid". Вид таблиц представлен на рис 1.

рис 1.
Для того чтобы не делать два вызова API к серверу, вот тут то и будем использовать цепочку промисов (асинхронных функции) когда первая функция (промис) выполняется и ее результат передается следующей функции в качестве параметра.
Каждый Promise заканчивается обработчиком .then. Пример цепочки промисов приведен на рис 2.
new Promise(function(resolve, reject) {
setTimeout(() => resolve(1), 1000); // (*)
}).then(function(result) { // (**)
alert(result); // 1
return result * 2;
}).then(function(result) { // (***)
alert(result); // 2
return result * 2;
}).then(function(result) {
alert(result); // 4
return result * 2;
Идея состоит в том, что результат первого промиса передаётся по цепочке обработчиков .then
.
Всё это работает, потому что вызов promise.then
тоже возвращает промис, так что мы можем вызвать на нём следующий .then
.
Когда обработчик возвращает какое-то значение, то оно становится результатом выполнения соответствующего промиса и передаётся в следующий .then
.
Более современный код написание это не использовать .then(function(result)) и функцию Fetch, а использовать await axios.get() и результат этой асинхронной функции будет передан в другую вызванную функцию с использованием обработчика .then.
На рис 3. показано ка это реализуется в моем проекте.
//2025
blockChain = async (e) => {
e.preventDefault();
const cityName = e.target.elements.cityInp.value;
console.log('blockChain city - ' + cityName);
const resultCity = await axios.get(process.env.REACT_APP_API_URL_TableCity +
`${cityName}`).then((resultCity) => {
alert("func 1 код города " + resultCity.data.rows[0].cityid);
var cityid = resultCity.data.rows[0].cityid;
const resultWeather = axios.get(process.env.REACT_APP_API_URL_TableWeather +
`${cityid}`).then((resultWeather) => {
alert("func 2 температура К " + resultWeather.data.rows[0].temperature);
});
});
}
//2025
Функция blockChain, будет запущена по нажатию кнопки код реализующей запуск представлен ниже рис 3. В результате используя цепочку промисов мы одной функцией реализуем ряд API вызовов на сервере. На стороне сервера это будет реализовано так рис 4.
//////Blockchain
//код в server.js
app.get(`/api/getTableWeather/:cityid`, cors(corsOptions), (req, res) => {
// console.log("You in getTableWeather - city is tablecity" + req.params.cityid);
request.getBlockWeatherByCityId(req)
.then((response) => {
res.status(200).send(response);
})
.catch((error) => {
res.status(500).send(error);
});
});
app.get(`/api/getTableCity/:city`, cors(corsOptions), (req, res) => {
//console.log("You in getTableCity - city is tablecity" + req.params.city);
request.getTableCity(req)
.then((response) => {
res.status(200).send(response);
})
.catch((error) => {
res.status(500).send(error);
});
});
//код в server.js
//код в querys.js
const getBlockWeatherByCityId = async (req,res) => {
console.log("мы в BlockChain getTableWeather" + "Город " + req.params.cityid);
try {
const res = await pool_weather.query(`SELECT cityid,temperature,
datetxt FROM tableweather WHERE cityid = $1`, [req.params.cityid]);
console.log(" Температурные данные города из таблицы tableruweather " +
res.rows[0]["cityid"] + " " + res.rows[0]["temperature"]);
return res;
} catch (err) {
console.log("Данные не получены!!" + err.stack);
}
};
const getTableCity = async (req, res) => {
//console.log("мы в getTableCity" + "Город " + req.params.city);
try {
const res = await pool_weather.query(`SELECT cityid, cityname,
lat, lon, country FROM tablecity WHERE cityname = $1`, [req.params.city]);
console.log("Данные tablecity " + res.rows[0]["cityname"] + " " +
res.rows[0]["cityid"] );
return res;
} catch (err) {
console.log("Данные не получены!!" + err.stack);
}
};
//код в querys.js
рис 4.
Для запуска формы ввода названия населенного пункта, используется компонента "InputFormBlockChain" рис 5,6.
<button
className="btnStartAsync"
onClick={() => this.btnClickAsync(this.state.display_noneA)}
>
Test Async paralell operathion!
</button>
<button
className="btnStartBlockChain"
onClick={() => this.btnClickBlockChain(this.state.display_noneB)}
>
Test Promice blockChain operathion!
</button>
<button
className="btnStartAsync"
onClick={() => this.btnClickTest()}
>
Test Operathion!
</button>
<div style={{ marginLeft: "15px" }} className="Changing_data_async">
<InputFormAsync
methodAction={this.paralleAsync}
>
Test Paralle Async
</InputFormAsync>
</div>
<div style={{ marginLeft: "15px" }} className="Changing_data_blockChain">
<InputFormBlockChain
methodAction={this.blockChain}
>
Test BlockChain
</InputFormBlockChain>
</div>

рис 4.
import React from "react";
import "bootstrap/dist/css/bootstrap.min.css";
const InputFormBlockChain= (props) => {
return(
<form className="form-container-actions" onSubmit={(e) => {
e.preventDefault();
props.methodAction(e);
}}>
<label className="labelForm" htmlFor="inputCity">Fill it out before
clicking the button</label>
<input className='selectData1' type='text' name='cityInp' placeholder={'City'}>
</input>
<br></br>
<button className="selectButtonAsync">{props.children}</button>
</form>
)
};
export default InputFormBlockChain;
рис 5.
Вводим данные и нажимаем кнопку, результаты выполнения цепочки будут получены если только каждый из промисов отработает без ошибок!. Первый промис вернул код города, передал его следующему промису, в виде параметра по которому осуществился отбор (для примера взята первая строка полученного набора строк).


Параллельные асинхронные операции
С цепочкой мы разобрались, теперь осталось рассмотреть то что позволяет использовать эти асинхронные функции параллельно что конечно влияет значительно на увеличение скорости выполнения API запросов которые могут быть направлены на различные ресурсы.
Вот тут то и включается вся мощь Promise.All, запустив одну функцию на фронтенде мы можем получить ряд различных ответов от сервера, и все запросы к различным ресурсам, таблицам баз данных будут выполняться параллельно!
Функция "paralleAsync" запускается также при вводе наименования населенного пункта и нажатии кнопки, также ка я пояснял когда рассматривали цепочку промисов.

Как это работает
На рис 1. функция "paralleAsync" в которой и запускается const [res, res2] = await Promise.all([datacity(city), dataweather(city)]), внутри мы видим асинхронные функции datacity(city) и dataweather(city) которые получают данные из таблиц "datacity" и "tableruweather". Результаты выполнения функций помещаются соответственно в res и res2.
//Test parallel load city and weather
paralleAsync = async (e) => {
e.preventDefault();
const city = e.target.elements.cityInp.value;
//console.log('paralleBlockChain city - ' + city);
const datacity = async (city) => {
try {
const res = await axios.get(process.env.REACT_APP_API_URL_TableCity + `${city}`);
// alert("func 1 data ", res.data.rows[0]);
return res;
} catch (err) {
console.log('Error city' + err);
}
}
const dataweather = async (city) => {
try {
const res2 = await axios.get(process.env.REACT_APP_API_URL_TableWeatherRu + `${city}`);
//alert("func 2 data", res2.data.rows[0].temperature);
return res2;
} catch (err) {
console.log('Error weather_ru' + err);
}
}
const [res, res2] = await Promise.all([datacity(city), dataweather(city)]);
//console.log('Результат из таблиц Promise.all ' + res.data.rows[0].cityid + ' ' + res2.data.rows[0].temperature);
alert('Результат из таблиц код города ' + res.data.rows[0].cityid + ' температура С ' + res2.data.rows[0].temperature)
}
Нажимаем кнопку и получаем результат рис 1. Результат также будет получен только при условии успешного выполнения каждой из функции обвернутых в Promise.All

Заключение
Подведя итого того что изложил выше, хочется еще сказать об аналогии асинхронных операций JavaScript c фоновыми операциями 1С. Я уже публиковал статью по "Длительным однопоточным и многопоточным операциям" и готовлю новую с замерами времени и прочими тонкостями. В 1С асинхронная функция это длительная операция выполняющееся в фоне (тот же async await) а многопоточное выполнение. разбиение по потокам (это тоже что Promice.All) параллельное выполнение высокозатратных по времени операции над данными.
Заранее всем спасибо! кто прочитает статью, возможно она кому то в чем то поможет, лично разрабатывая сейчас проекты на 1С, я очень часто включаю в код разработки использования "длительных операции". Но а на языке JavaScript в разработке на React это называется асинхронная операция и она везде в коде.
До новых встреч на Habr и успешной разработки всем кто этим занимается!
SPS. Lipetsk 2025г.
Проект "Weather" в котором рассматривалась тема промисов рис . ниже


