Форум программистов, компьютерный форум, киберфорум
JavaScript для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.62/21: Рейтинг темы: голосов - 21, средняя оценка - 4.62
0 / 0 / 0
Регистрация: 18.08.2016
Сообщений: 23

Асинхронный запрос в цикле XMLHttpRequest неправильная работа

04.02.2019, 01:04. Показов 4434. Ответов 7

Студворк — интернет-сервис помощи студентам
Доброго времени суток уважаемые пользователи.
Уже 4 часа бьюсь над выполнением задания.
Необходимо создать асинхронный запрос в цикле с выборкой параметров.
Что делаю:
0. Создаю массив:
JavaScript
1
var iHost = ['http://192.168.1.61/gpio.js','http://192.168.1.59/gpio.js','http://192.168.1.68/gpio.js'];
1. Создаю новый объект:
JavaScript
1
iObject = new XMLHttpRequest();
2. Создаю цикл(запуск по таймеру (setTimeout)):
JavaScript
1
for (var i = 0; i < iHost.length; i++){
3. Формирую запрос:
JavaScript
1
iObject.open('GET', iHost[i]);
4. Далее обработчик после вызывающийся после iObject.send();
JavaScript
1
2
3
4
5
6
7
8
9
iObject.onreadystatechange = function(){
if (iObject.readyState != 4){console.log ('Состояние: ' + iObject.readyState + 'Счетчик: ' + i); return; }
if (iObject.status !== 200){ console.log ('Страница не готова.'); }
else{
iValue = iObject.responseText;
iValue = iValue.match(/[{].*[}]/);
iValue = JSON.parse(iValue);
window.iStatus = iValue;
}
5. Далее отправка:
JavaScript
1
iObject.send();
При выполнении скрипта результат выдается только для последнего элемента массива, а нужно для всех.
Что пробовал?:
Менял местами пункты 1 и 2. - не помогло
Пробовал использовать вместо iObject.onreadystatechange - iObject.onload - не помогло
Что дальше делать ума не приложу, мозг уже дымится, прошу вашей помощи.

Весь код:
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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
var timerLight = setTimeout(function run(){
    for (var i = 0; i < iHost.length; i++){
    console.log (iHost[i] + 'Счетчик: ' + i);
    http = iHost[i];
    iObject = new XMLHttpRequest();
    iObject.open('GET', http);
    
    iObject.onreadystatechange = function(){
        console.log (iObject);
        if (iObject.readyState != 4){console.log ('Состояние: ' + iObject.readyState + 'Счетчик: ' + i); return; }
        if (iObject.status !== 200){ console.log ('Страница не готова.'); }
        else{
        console.log(i);
        iValue = iObject.responseText;
        iValue = iValue.match(/[{].*[}]/);
        iValue = JSON.parse(iValue);
        window.iStatus = iValue;
}}      
    
    iObject.send();
    
    if (!!window.iStatus.dj0){
    console.log(iStatus);
        switch(i){
            case 0:
            if (iStatus.dj0.st == '0'){
            iButton_room1.innerHTML = "";}
            else{
            iButton_room1.style.left = "94px";
            iButton_room1.style.transition = "all 0.2s ease-in-out";}                        
            break;
            case 1:
            if (iStatus.dj0.st == '0'){
            iButton_hall.innerHTML = "";}
            else{
            iButton_hall.style.left = "94px";
            iButton_hall.style.transition = "all 0.2s ease-in-out";}                        
            break;
            case 2:
            if (iStatus.dj0.st == '0'){
            iButton_wash.innerHTML = "";}
            else{
            iButton_wash.style.left = "94px";
            iButton_wash.style.transition = "all 0.2s ease-in-out";}
            break;
            }
    }
    if (!!window.iStatus.dj1){
        switch(i){
            case 0:
            if (iStatus.dj1.st == '0'){
            iButton_room2.innerHTML = "";}
            else{
            iButton_room2.style.left = "94px";
            iButton_room2.style.transition = "all 0.2s ease-in-out";}
            break;
            case 2:
            if (iStatus.dj1.st == '0'){
            iButton_kitchen.innerHTML = "";}
            else{
            iButton_kitchen.style.left = "94px";
            iButton_kitchen.style.transition = "all 0.2s ease-in-out";}
            break;
            }
    }
    setTimeout(100);
    delete iObject;
    }
    timerLight = setTimeout(run, 5000);
}, 5000);
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
04.02.2019, 01:04
Ответы с готовыми решениями:

XMLHttpRequest запрос
Ситуация следующая. Есть сервер VPS, на котором стоит приложение Node.js. К нему необходимо сделать запрос от &quot;клиента&quot;...

XMLHttpRequest не отправляет запрос
Всем привет. Есть у меня простая задачка, с помощью VK api вытащить инфу о пользователе и отобразить на странице. Пытаюсь отправлять...

Сделать XMLHttpRequest запрос на http
Всем привет. Ситуация такая: Есть один сайт А с которого делает XMLHttpRequest запрос на сайт В у которого есть только http, а https нет....

7
24 / 18 / 9
Регистрация: 27.04.2017
Сообщений: 122
04.02.2019, 04:20
Колбэки, переданные в setTimeout помещаются в специальную очередь - callback Queue (структура типа First In First Out).
Функции из этой очереди будут выполнены только после выполнения всего синхронного кода.

Цикл - это синхронный код. Поэтому сначала буду выполнены все итерации цикла, и уже после этого вызовутся функции из Callback Queue.
1
27 / 19 / 8
Регистрация: 21.08.2018
Сообщений: 39
04.02.2019, 06:18
setTimeOut здесь роли не играет, но он всё по делу сказал.
При вызове функции run() происходит следующее:
1. Итерация цикла, в которой ты глобально объявляешь переменные iObject , http(или они уже задекларированы заранее) проделываешь необходимые присваивания и задаешь callback для onreadystatechange.
2. iObject.send(); - Асинхронно осуществляешь запрос.
3. JS не ждёт выполнения запроса, соответственно продолжает выполнять код, делает все проверки, удаляет объект iObject.
Начинает следующую итерацию цикла, идём к пункту 1.

Всё это происходит всего 3 раза, в этот момент все 3 асинхронных запроса уже выполнено. JS начинает эти коллбеки выполнять - все они обращаются к iObject, но он удалён. Если его не удалять каждую итерацию - он будет содержать в себе только ответ последнего запроса. И счётчик показывает тебе всегда i=3, потому что цикл весь уже выполнен.

Решения: добавить для iObject.open('GET', http); третий параметр false для синхронного выполнения, тогда нужно отказаться от коллбэка и обрабатывать запрос сразу после iObject.send.

Либо обернуть содержимое цикла в функцию, которая обеспечит через замыкание уникальность объекта iObject

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
var timerLight = setTimeout(function run(){
    for (var i = 0; i < iHost.length; i++){
    (function(i) {
    console.log (iHost[i] + 'Счетчик: ' + i);
    http = iHost[i];
    var iObject = new XMLHttpRequest();
    iObject.open('GET', http);
    
    iObject.onreadystatechange = function(){
        console.log (iObject);
        if (iObject.readyState != 4){console.log ('Состояние: ' + iObject.readyState + 'Счетчик: ' + i); return; }
        if (iObject.status !== 200){ console.log ('Страница не готова.'); }
        else{
        console.log(i);
        iValue = iObject.responseText;
        iValue = iValue.match(/[{].*[}]/);
        iValue = JSON.parse(iValue);
        window.iStatus = iValue;
}}      
    
    iObject.send();})(i);
    
  
    }
  
}, 5000);
1
 Аватар для atanov
640 / 481 / 172
Регистрация: 26.05.2016
Сообщений: 2,674
04.02.2019, 07:30
AlexanderTravki, ну а promise никак не подойдёт? Особливо с fetch.
1
0 / 0 / 0
Регистрация: 18.08.2016
Сообщений: 23
04.02.2019, 08:00  [ТС]
Если поставить false, то код работает, я сначала так и сделал, но код подормаживает(код управляет состоянием замкнутости рэле, а пока он выполняется не вызвать onclick кнопки). Как обернуться тело цикла не совсем понятно, ведь в функции он будет выполняться также 3 раза возвращать опять же i = 3 (host[3]). Прошу прощения за глупые вопросы, видимо не до конца понимаю алгоритмически, того что получится.
0
Эксперт JS
2037 / 1096 / 409
Регистрация: 29.04.2016
Сообщений: 2,625
04.02.2019, 09:30
AlexanderTravki,

Если просто обойти все адреса в массиве и дождаться ответа то можно проще -> http://some-test.onlinewebshop.net/cycle-fetch/
HTML5
1
<div id="res"></div>
JavaScript
1
2
3
4
5
6
7
let iHost = ['http://some-test.onlinewebshop.net/cycle-fetch/gpioLog.php','http://some-test.onlinewebshop.net/cycle-fetch/gpioPass.php','http://some-test.onlinewebshop.net/cycle-fetch/gpioCity.php'];
 
let timerLight = setTimeout(run => {
    for(let e of iHost) fetch(e).then(res => res.json()).then(html => res.innerHTML += JSON.stringify(html) + '<br>');
}, 500);
 
timerLight();
PHP
1
2
3
4
5
6
7
8
9
10
11
12
// gpioLog.php
$arr['gpioLog'] = 'Вася';
echo json_encode($arr);
 
// gpioPass.php
$arr['gpioPass'] = '55555';
echo json_encode($arr);
 
// gpioCity.php
sleep(2);  // для задержки ответа от сервера
$arr['gpioCity'] = 'Москва';
echo json_encode($arr);
1
0 / 0 / 0
Регистрация: 18.08.2016
Сообщений: 23
05.02.2019, 01:22  [ТС]
Написал вот такой код, правда еще нет кода переключающего состояния кнопок, но всё равно решил выложить на ваш суд. Сегодня после работы изучал "Promise", в одной из статей написано, что нельзя совмещать синхронный код и асинхронный (т.е. мне теперь все оборачивать промисами? вообще когда его нужно применять, а когда нет?)

Добавлено через 31 минуту
Прошу прощения отправил код с ошибками
Вот рабочий:
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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
<script>
var iKitLink = ['http://192.168.1.59/gpio.js','http://192.168.1.61/gpio.js','http://192.168.1.68/gpio.js'];
var statusHall0;
var statusHall1;
var statusRoom0;
var statusRoom1;
var statusRest0;
var statusRest1;
 
 
function httpConnect(counter){
    let promise = new Promise(function(resolve,reject){
        var xhr = new XMLHttpRequest();
        xhr.open('GET',counter);
        xhr.onload = function(){if (xhr.readyState == 4 && xhr.status == 200); resolve(xhr.response);}
        xhr.onerror = function(){reject(new error('Network filed.'));}
        xhr.send();
    }); 
    promise.then(function(response){
        console.log(response);
        getStatatus(response);
        
    });
    promise.catch(function(error){
        console.log(error);
    }); 
}
 
function getStatatus(response){
    let promise = new Promise(function(resolve){
        var answer = response.match(/[{].*[}]/);
        answer = JSON.parse(answer);
        if (!!answer){ resolve(answer);}
    });
    promise.then(function(resolve){ 
    if (resolve.ip == '192.168.1.59'){
        if (!!resolve.dj0){
            window.statusHall0 = resolve.dj0.st;}
        else{
            window.statusHall0 = 'null';}
        if (!!resolve.dj1){
            window.statusHall1 = resolve.dj1.st;}
        else{
            window.statusHall1 = 'null';}
    }
    //if (answer.ip == '192.168.1.61'){
        //if (!!answer.dj0){
            //statusRoom0 = answer.dj0.st;}
        //else{
            //statusRoom0 = 'null';}
        //if (!!answer.dj1){
            //statusRoom1 = answer.dj1.st;}
        //else{
            //statusRoom1 = 'null';}
    //}
    //if (answer.ip == '192.168.1.68'){
        //if (!!answer.dj0){
            //statusRest0 = answer.dj0.st;}
        //else{
            //statusRest0 = 'null';}
        //if (!!answer.dj1){
            //statusRest1 = answer.dj1.st;}
        //else{
            //statusRest1 = 'null';}
    console.log('КОРИДОР: ' + window.statusHall0 + ' ; ' + window.statusHall1);
    });     
    promise.catch(function(error){
        console.log(error);
    }); 
    //console.log('КОМНАТА: ' + statusRoom0 + ' ; ' + statusRoom1);
    //console.log('ВАННАЯ: ' + statusRest0 + ' ; ' + statusRest1);    
};  
 
 
var timerON= setTimeout(function run(){
for (let i of iKitLink) { httpConnect(i); }
timerON = setTimeout(run, 10000);
}, 100);
</script>
0
Эксперт JS
6496 / 3907 / 2006
Регистрация: 14.06.2018
Сообщений: 6,781
05.02.2019, 09:57
Скрипт, который нормально мониторит ответы от 6 датчиков.
Интервал опроса выставлен в 1 секунду. Адреса датчиков нужно выставить свои.
PHP/HTML
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
57
58
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
</head>
<body>
    <form id="all">
        <div class="f0">
            <label>192.168.1.59: </label>
            <input class="dj0" />
            <input class="dj1" />
        </div><br />
        <div class="f1">
            <label>192.168.1.61: </label>
            <input class="dj0" />
            <input class="dj1" />
        </div><br />
        <div class="f2">
            <label>192.168.1.68: </label>
            <input class="dj0" />
            <input class="dj1" />
        </div><br />
        <button type="button" id="start">Начать мониторинг</button>
        <button type="button" id="stop">Остановить мониторинг</button>
    </form>
    <script>
        let iHost = ["gpio59.js", "gpio61.js", "gpio68.js"];
        let all = document.getElementById("all");
        let intervalId;
        document.getElementById("start").onclick = e => { intervalId = setInterval(getData, 1000); }; // Каждую секунду
        document.getElementById("stop").onclick = e => { clearInterval(intervalId); };
 
        async function getData() {
            for (let i = 0; i < iHost.length; i++) {
                let t0 = all.querySelector(".f" + i + " .dj0"),
                    t1 = all.querySelector(".f" + i + " .dj1");
                try {
                    let response = await fetch(iHost[i]);
 
                    if (response.ok) {
                        let json = await response.json();
                        t0.value = json.dj0.st;
                        t1.value = json.dj1.st;
                    }
                    else {
                        t0.value = "null";
                        t1.value = "null";
                    }
                }
                catch (e) {
                    t0.value = "null";
                    t1.value = "null";
                }
            }
        }
    </script>
</body>
</html>
Цитата Сообщение от AlexanderTravki Посмотреть сообщение
вообще когда его нужно применять, а когда нет?
Асинхронный код должен быть от начала и до конца.
Конец - терминальная ловушка асинхронности. Это async void метод, который в JS может быть IIFE или обработчиком события, например нажатия на кнопку.
Терминальная ловушка асинхронности - практически последний шанс обработать исключение из асинхронного кода.
Первоисточники из C#:
Стивен Клири написал книгу по асинхронности. Тут его статья.
http://www.oszone.net/21402/
Документация Microsoft по Task Asynchronous Pattern (TAP)
Асинхронный шаблон, основанный на задачах (TAP)
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
05.02.2019, 09:57
Помогаю со студенческими работами здесь

Кросс-доменный XMLHttpRequest запрос
После GET запроса, Не удаётся прочесть ответ сервера, т.к. сервер не добавляет заголовок &quot;Access-Control-Allow-Origin&quot; в ответ. ...

Не могу сделать запрос XMLHttpRequest (POST)
Подскажите рабочий пример POST запроса, ничего не нашел, другие примеры пробовал - они не работают, запрос просто не проходил...

XmlHttpRequest запрос (отправка данных на label и ответ с сайта)
Имеется блокнот с неким словом на русском языке, к примеру, словом &quot;мама&quot;. Нужно отправить это слово на сайт sozdik.kz(русско-казахский...

Покажите асинхронный запрос ajax
хотя бы на одном &lt;input&gt; хочу регистрацию сделать на ajax, а не могу его осилить...(

Как превратить синхронный запрос, в асинхронный?
Всем добра. Есть скрипт, который нажимает на сайте кнопочки. Кнопочек довольно много. Какую нажимать решает алгоритм, на сервере. Скрипт...


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

Или воспользуйтесь поиском по форуму:
8
Ответ Создать тему
Новые блоги и статьи
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru