Форум программистов, компьютерный форум, киберфорум
JavaScript
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
0 / 0 / 0
Регистрация: 09.12.2019
Сообщений: 7

Отправка множества fetch запросов через Promise.All и отлов "ошибок"

15.02.2024, 14:25. Показов 511. Ответов 2

Студворк — интернет-сервис помощи студентам
Добрый день. Сразу прошу прощения, если неправильно использую какие-то термины, начал заниматься этой темой не так давно.
По работе возникла необходимость проверять активацию смартфонов, но через сайт сервиса, занимающегося их обслуживанием, можно проверять только одно устройство за раз. Погуглил, поискал информацию, и написал небольшую страничку с использованием только JS (+jQuery), HTML и CSS, чтобы можно было разместить её на Github Pages.
Принцип работы простой. На странице есть текстовое поле, кнопка и таблица. В текстовое поле вставляется список IMEI устройств, каждый в новой строке, без разделителей и лишних символов. При нажатии на кнопку отсеиваются лишние значения (в IMEI должно быть только 15 цифр). На основе этого списка создаются фетч-запросы (сам запрос вытянул через инструменты разработчика с оригинального сайта, возможно в нем есть что-то лишнее):
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
function createFetch(data = {}) {
    return fetch(API_URL, {
        method: 'POST',
        mode: 'cors',
        cache: 'no-cache',
        credentials: 'omit',
        headers: {
            'accept': 'application/json, text/plain, */*',
            'accept-language': 'ru,en-US;q=0.9,en;q=0.8,ru-RU;q=0.7,id;q=0.6,de;q=0.5,ar;q=0.4',
            'content-type': 'application/json;charset=UTF-8',
            'sec-ch-ua': '\'Not_A Brand\';v=\'8\', \'Chromium\';v=\'120\', \'Google Chrome\';v=\'120\'',
            'sec-ch-ua-mobile': '?0',
            'sec-ch-ua-platform': '\'Windows\'',
            'sec-fetch-dest': 'empty',
            'sec-fetch-mode': 'cors',
            'sec-fetch-site': 'same-site',
            'sign': '12c0d63d0005ec61c364845d974b9b62',
            'Referer': 'https://www.carlcare.com/',
            'Referrer-Policy': 'strict-origin-when-cross-origin'
        },
        redirect: 'follow',
        reffererPolicy: 'strict-origin-when-cross-origin',
        body: JSON.stringify(data),
    }).then((response) => {
        return response.json();
    });
}
Мне нужно было иметь возможность вывести в таблицу результаты в том же порядке, в котором они были в текстовом поле, поэтому я засовываю промисы, которые возвращает вышеуказанная функция, в массив, который потом использую в Promise.All():
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
function checkWarranty() {
    $(BLOCKER_SELECTOR).css('display', 'flex');
    let imeiArray = $(TEXTAREA_SELECTOR).val().split('\n');
    imeiArray = imeiArray.filter((temp) => IMEI_REGEXP.test(temp));
    //console.log(imeiArray);
 
    promiseArray = new Array();
    imeiArray.forEach((imei) => {
        if ($('tr#'+imei).length == 0) {
            let dataString = {"shortName" : "ru", "imei" : imei};
            promiseArray.push(createFetch(dataString));
        }
    });
 
    Promise.all(promiseArray).then((results) => {
        results.forEach((result) => {
            const temp = processData(result);
            if (temp!=null) {
                insertRow(temp);
            }
        });
        $(BLOCKER_SELECTOR).css('display', 'none');
    });
    
    
}
И все бы было хорошо, но иногда ответ на запрос я получаю не тот, что хотел бы.
Обычно ответ выглядит как-то так:
JSON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
    "status": 200,
    "message": "success",
    "result": {
        "status": 3,
        "warrantyDuration": "2020-09-23",
        "brand": "TECNO",
        "model": "CF7",
        "imei": [
            "359050097375085",
            "359050097375093",
            "",
            ""
        ],
        "activeTime": "2019-08-23 00:00:00"
    },
    "timestamp": 1705043556752
}
Но иногда может вернуться такое:
JSON
1
2
3
4
5
6
{
    "status": 200,
    "message": "success1",
    "result": null,
    "timestamp": 1705043555672
}
Причем всегда при повторе запроса все нормально.

Раньше я делал немного по другому, проходился по списку IMEI через forEach и использовал рекурсивную функцию со счетчиком повторений, что-то такое:
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
async function sendRequest(url='', data={}) {
    let response = await fetch(url, {
        method: 'POST',
        mode: 'cors',
        cache: 'no-cache',
        credentials: 'omit',
        headers: {
            'accept': 'application/json, text/plain, */*',
            'accept-language': 'ru,en-US;q=0.9,en;q=0.8,ru-RU;q=0.7,id;q=0.6,de;q=0.5,ar;q=0.4',
            'content-type': 'application/json;charset=UTF-8',
            'sec-ch-ua': '\'Not_A Brand\';v=\'8\', \'Chromium\';v=\'120\', \'Google Chrome\';v=\'120\'',
            'sec-ch-ua-mobile': '?0',
            'sec-ch-ua-platform': '\'Windows\'',
            'sec-fetch-dest': 'empty',
            'sec-fetch-mode': 'cors',
            'sec-fetch-site': 'same-site',
            'sign': '12c0d63d0005ec61c364845d974b9b62',
            'Referer': 'https://www.carlcare.com/',
            'Referrer-Policy': 'strict-origin-when-cross-origin'
        },
        redirect: 'follow',
        reffererPolicy: 'strict-origin-when-cross-origin',
        body: JSON.stringify(data),
    });
    return response.json();
}
 
 
function tryRequest(dataString, tryCount) {
    switch(tryCount) {
    case 0:
        console.error(`Не удалось проверить гарантию: ${dataString}`);
        break;
 
    default:
        sendRequest(API_URL, dataString).then((data) => {
            const temp = processData(data)
            if (temp != null) {
                insertRow(temp);
            }
            else {
                tryRequest(dataString, tryCount-1);
            }
        });
        break;
    }
}
Это решает проблему, но запросы выполняются в случайном порядке, да и отсортировать их не получается -- я не знаю, когда все созданные запросы закончат выполняться, чтобы отсортировать результаты.
Подскажите, в какую сторону копать? Потому что для меня самый очевидный вариант -- прямо в коде запустить промисы два раза подряд (ну поскольку с первого нажатия кнопки часть результатов получаются с ошибкой, а на втором оставшиеся "доходят" правильно), но звучит это как-то неправильно.
Исходники прикрепляю в архивах, старая версия -- с fetch через forEach, новая -- с fetch через Promise.All().
Вложения
Тип файла: zip carlcare-warranty-checker-old-version.zip (1.07 Мб, 0 просмотров)
Тип файла: zip carlcare-warranty-checker-main.zip (1.07 Мб, 0 просмотров)
0
Лучшие ответы (1)
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
15.02.2024, 14:25
Ответы с готовыми решениями:

Promise, два ajax запроса, задать очередь выполнения запросов, цепочка promise
Добрый день, уважаемые форумчане! Помогите разобраться с цепочкой promise. Суть проблемы: Есть 3 метода: 2 ajax get запроса и 1...

SSRS как использовать параметры при создании запросов через fetch?
Делал запросы через SQL скрипт и как туда подставить параметры я представляю. Но как подставить параметры через fetch? Например, есть такая...

Перехват всех запросов, отправка ошибок логгирование исключений
Не понял как вбить запрос в гугле так, чтобы он мне ответил как надо, поэтому спрошу тут :) Через какой класс множно перехватить все...

2
 Аватар для voraa
1289 / 1266 / 187
Регистрация: 21.01.2024
Сообщений: 5,816
15.02.2024, 18:12
Лучший ответ Сообщение было отмечено hit3nkuro как решение

Решение

А что, если в функции sendRequest делать повторный запрос, если первый не дал результата?
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
async function sendRequest(url = '', data = {}) {
    function req() {
        return fetch(url, {
            method: 'POST',
            mode: 'cors',
            cache: 'no-cache',
            credentials: 'omit',
            headers: {
                accept: 'application/json, text/plain, */*',
                'accept-language':
                    'ru,en-US;q=0.9,en;q=0.8,ru-RU;q=0.7,id;q=0.6,de;q=0.5,ar;q=0.4',
                'content-type': 'application/json;charset=UTF-8',
                'sec-ch-ua':
                    "'Not_A Brand';v='8', 'Chromium';v='120', 'Google Chrome';v='120'",
                'sec-ch-ua-mobile': '?0',
                'sec-ch-ua-platform': "'Windows'",
                'sec-fetch-dest': 'empty',
                'sec-fetch-mode': 'cors',
                'sec-fetch-site': 'same-site',
                sign: '12c0d63d0005ec61c364845d974b9b62',
                Referer: 'https://www.carlcare.com/',
                'Referrer-Policy': 'strict-origin-when-cross-origin',
            },
            redirect: 'follow',
            reffererPolicy: 'strict-origin-when-cross-origin',
            body: JSON.stringify(data),
        });
    }
    const resp = await req();
    const json = await resp.json();
    if (json.result) return json;
    // Повторный запрос, усли в первом нет результата
    const resp1 = await req();
    const json1 = await resp1.json();
    return json1;
}
1
0 / 0 / 0
Регистрация: 09.12.2019
Сообщений: 7
16.02.2024, 14:44  [ТС]
Цитата Сообщение от voraa Посмотреть сообщение
А что, если в функции sendRequest делать повторный запрос, если первый не дал результата?
Это код из старого варианта. Я смог там добиться отсутствия ошибки через функцию tryRequest (tryCount по умолчанию выставлял 3).
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function tryRequest(dataString, tryCount) {
    switch(tryCount) {
    case 0:
        console.error(`Не удалось проверить гарантию: ${dataString}`);
        break;
 
    default:
        sendRequest(API_URL, dataString).then((data) => {
            const temp = processData(data)
            if (temp != null) {
                insertRow(temp);
            }
            else {
                tryRequest(dataString, tryCount-1);
            }
        });
        break;
    }
}
Но опять же, ошибок я там не ловлю, но и отследить окончание выполнения всех запросов не могу.

Возникла мысль, пытаюсь сформулировать. fetch() возвращает промис. Я могу выполнять несколько промисов асинхронно, но тогда не буду знать когда закончится их выполнение. Либо я могу выполнить их через Promise.All(), но тогда, если я положу в него просто массив из fetch, то я не смогу повторить их, если возвращаемый результат меня не устроит.
А если я буду создавать массив промисов, каждый из которых вызывает функцию tryRequest, которая будет принимать промис создаваемый через fetch. И потом использую этот массив в Promise.All(). Получается, и ошибки скорее всего уйдут, и результатом будет массив ответов в том же порядке, что и введенные пользователем IMEI.
Попробую переписать код и посмотрю что получится...

Добавлено через 8 минут
UPD. Теперь понял мысль. Да, можно и вашим вариантом попробовать, он и проще будет
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
16.02.2024, 14:44
Помогаю со студенческими работами здесь

отправка запросов к через XML
Здравствуйте! Помогите начинающему: нужно сформировать с помощью формы запрос в формате XML, отправить его по адресу, получить ответ в...

отправка запросов к через XML
Здравствуйте! Помогите начинающему: нужно сформировать с помощью формы запрос в формате XML, отправить его по адресу, получить ответ в...

Отправка запросов через формы
Здравствуйте программисты. Я создаю сервис для онлайн тестирования знаний по определенному сериалу. Суть в том что пользователь должен...

Отправка запросов через промежутки времени
Использую Retrofit. Нужно условно каждые 5 сек отправлять запрос на сервер. Как это можно реализовать? Мой код: import...

Отправка ussd запросов через модем
Всем привет. Проблема вот в чем: я подключаюсь к модему, используя библиотеку COMPortLib и мне постоянно вылетает в лог ^RSSI:24, ну или...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
3
Ответ Создать тему
Новые блоги и статьи
Модель ЗдрввоСохранения 7: больше работников, больше ресурсов.
anaschu 08.04.2026
работников и заданий может быть сколько угодно, но настроено всё так, что используется пока что только 20% kYBz3eJf3jQ
Дальние перспективы сервера - слоя сети с космологическим дизайном интефейса карты и логики.
Hrethgir 07.04.2026
Дальнейшее ближайшее планирование вывело к размышлениям над дальними перспективами. И вот тут может быть даже будут нужны оценки специалистов, так как в дальних перспективах всё может очень сильно. . .
Горе от ума
kumehtar 07.04.2026
Эта мне ментальная установка, что вот прямо сейчас, мол, мне для полного счастья не хватает (нужное вписать), и когда я этого достигну - тогда и полный кайф. Одна из самых сильных ловушек на пути. . . .
Использование значений реквизитов справочника в документе, с определенными условиями и правами
Maks 07.04.2026
1. Контроль срока действия договора Алгоритм из решения ниже реализован на примере нетипового документа "ЗаявкаНаРаботу", разработанного в конфигурации КА2. Задача: уведомлять пользователя, если. . .
Доступность команды формы по условию
Maks 07.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: сделать доступной кнопку (команда формы "ЗавершитьСписание") при. . .
Уведомление о неверно выбранном значении справочника
Maks 06.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "НарядПутевка", разработанного в конфигурации КА2. Задача: уведомлять пользователя, если в документе выбран неверный склад. . .
Установка Qt Creator для C и C++: ставим среду, CMake и MinGW без фреймворка Qt
8Observer8 05.04.2026
Среду разработки Qt Creator можно установить без фреймворка Qt. Есть отдельный репозиторий для этой среды: https:/ / github. com/ qt-creator/ qt-creator, где можно скачать установщик, на вкладке Releases:. . .
AkelPad-скрипты, структуры, и немного лирики..
testuser2 05.04.2026
Такая программа, как AkelPad существует уже давно, и также давно существуют скрипты под нее. Тем не менее, прога живет, периодически что-то не спеша дополняется, улучшается. Что меня в первую очередь. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru