• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Повторная загрузка спрайта при ошибке подключенияк нему

Ildarmustafin86

Active member
Добрый день уважаемые форумчане. Прошу подсказать или на направить меня нужное направление.
В html файле веб-сервера делаю подключение js и css. При ошибке подключения происходит повторное подключение js и css. Все работает как мне нужно. Но у меня не получается
сделать повторную загрузку спрайта(css_sprites.png завязан на иконки) при onerror. Спрайт css_sprites.png загружается в css в background-image.
<!doctype html>
<html lang="ru">
<head>
<script>
function reopenJS(scriptPath){
let script = document.createElement('script');
script.src = scriptPath;
document.head.append(script);
script.onerror = function() {
reopenJS(scriptPath);
}
}
</script>
<link rel="stylesheet" type="text/css" href="style.css" onerror="reopenJS('style.css');">
<link rel="stylesheet" type="text/css" href="bootstrap.min.css" onerror="reopenJS('bootstrap.min.css');">
<script src="chartist.min.js" charset="utf-8" onerror="reopenJS('chartist.min.js');"></script>
<script src="functions.js" onerror="reopenJS('functions.js');"></script>
</head>
В файле functions.js скрипты открываются как:
function openSchedule() {
event.preventDefault();
let xhttp = new XMLHttpRequest();
xhttp.open("GET", 'config.json', true);
xhttp.timeout = 10000;
xhttp.ontimeout = function (e) {
console.log("[TIMEOUT] OpenSchedule");
openSchedule();
};
xhttp.onerror = function() {
console.log("[ERROR] Reopen OpenSchedule");
openSchedule();
};
xhttp.onabort = function () {
console.log("[ABORT] OpenSchedule");
};
xhttp.onload = function () {
if (this.readyState == 4 && this.status == 200) {
...
};
xhttp.send();
}
.temp {
height:32px;
width:32px;
background-position:0 -34px;
text-decoration:none;
background-color:transparent;
background-image:url(images/css_sprites.png);
margin:3px;
display:inline-block;
}
 

enjoynering

Well-known member
Я какой header возвращает сервер? Если конечно возвращает. Его можно посмотреть в developer mode в закладке network.
 

Ildarmustafin86

Active member
Вкладка Headers:
Код:
General:
Request URL: http://192.168.0.13/images/css_sprites.png
Referrer Policy: strict-origin-when-cross-origin

Response Headers:
HTTP/1.1 200 OK
Content-Type: image/png
Content-Length: 11934

Request Headers:
GET /images/css_sprites.png HTTP/1.1
Referer: http://192.168.0.13/style.css
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36
DNT: 1
 

Ildarmustafin86

Active member
Ошибку timeout возвращает редко. но ее я хочу перехватить и обработать. Все остальные таймауты я перехватил успешно
 

enjoynering

Well-known member
Странно у вас в header

HTTP/1.1 200 OK
Content-Type: image/png
Content-Length: 11934

Но при этом timeout.
 

Ildarmustafin86

Active member
Дали решение на другом форуме:
.temp {
height:32px;
width:32px;
background-position:0 -34px;
text-decoration:none;
background-color:transparent;
background-image:var(--img, url(images/css_sprites.png));
margin:3px;
display:inline-block;
}
</script>
function loadImage(src) {
const img = new Image();
img.src = src;
img.decode()
.then(() => {
document.body.style.setProperty('--img', 'url('+src+')');
})
.catch(() => {
console.log("[ERROR] Reopen SPRITE");
loadImage(src);
})
}
</script>
loadImage('images/css_sprites.png');

Переделал под себя:
function loadImage(src) {
const img = new Image();
img.src = src;
img.onload = function() {
//console.log("SPRITE LOAD");
document.body.style.setProperty('--img', 'url('+src+')');
}
img.onerror = function() {
console.log("[ERROR] Reopen SPRITE");
loadImage(src);
}
}
loadImage('images/css_sprites.png');
 

enjoynering

Well-known member
Прикольно. Спасибо. А вы не пробовали грузить Bootstrap в зависимости есть или нету интернета? Если есть то грузим его с хостинга в инете. Нету инета, грузим с esp8266.
 

enjoynering

Well-known member
Я делал, оно даже работало, но было 2 беды. Грузилось не в попад. У меня жёсткая зависимость одной js от другой. Но вторая иногда грузилась первой и сразу вываливала ошибку. Вторая проблема, при определённых условиях подгружались обе версии сразу - из инета и из esp8266. Победить все это я не смог и отказался от этой затеи. Если у вас получится оно того стоит - скорость загрузки страниц возрастает раза в 1.5
 

yurik72

Member
Корень всех проблем в том , что на стоковых библиотеках ESP8266/ESp32 может в один момент времени обрабатывать только один запрос. Поэтому такая куча и непредсказуемость. то загрузиться то нет.
Два Выхода
1. Продолжать совершенствовать javascript, таким образом чтобы чтобы след. запрос не начинался пока предыдущий не закончился
вот пример (только для идеи !)как это сделать. из которого нужно вызывать функцию doFetchQueue ... она не начнет новый запрос, пока предыдущий , вызванный этой же функцией не закончиться
function doFetch(apiurl, callback,cberror,setBusy) {
// console.log("dofetch");
// console.log(apiurl);
if (setBusy) {
onProgress(true);
}

fetch(apiurl)
.then(response => {

if (setBusy && fetchqueue.length === 0) {
onProgress(false);
}

//console.log(response);
if (response.status === 200) {
return response.json()
}
else {

console.log("Error fetch" + apiurl)
if (cberror)
cberror();
}
}
)
.then(data => callback(data))
.catch(function (error) {
console.log("ops ! fetch is fail on iteration " + apiurl)
console.log(error);
if (cberror)
cberror();
});
}
var fetchqueue = [];
var runingqueue = [];
function doFetchQueue(apiurl, callback) {
console.log("doFetchQueue" + apiurl);

//var runimmediat = fetchqueue.length === 0;
//if (runimmediat)
// console.log("run");
fetchqueue.push({
apiurl: apiurl,
callback: (data) => {
if (callback)
callback(data);
console.log("Queue completed");
console.log(apiurl);
runingqueue.shift();
doFetchFromQueue();
},
cberror: () => {
console.log("Error from queue");
runingqueue.shift();
}
});
//console.log(fetchqueue.length);
if (runingqueue.length===0)
doFetchFromQueue();
}
function doFetchFromQueue() {
if (fetchqueue.length === 0) return;
console.log("from Queue");
const execparam = fetchqueue.shift();
console.log(execparam);
runingqueue.push(execparam);
doFetch(execparam.apiurl, execparam.callback, execparam.cberror, true);
}


2. Использовать библиотеку https://github.com/me-no-dev/ESPAsyncWebServer.. Она позволяет обрабатывать одновременные запросы
 

Ildarmustafin86

Active member
Попробовал асинхронный веб сервер. Понравилось. Если раньше файловая система загружалась 8-10 сек, то теперь она загружается за 2-3 сек. Буду переделывать весь проект.
 

yurik72

Member
Ну скорости он не прибавляет. Просто нет ошибок одновременного доступа вот и видимость что быстро
А еще обожми свои скрипты gzip и не нарадуешься. У меня сложный проект React Js. в обжатом виде скрипт 98 килобайт грузиться с нуля за 5-7 сек
 

Ildarmustafin86

Active member
Они у меня уже в gzip. Теперь я думаю можно и jQuery использовать. А то из за долгой загрузки пришлось отказаться от него
 

enjoynering

Well-known member
Вы Cache-Control header используете? Проект с jquery притормажиает только первый раз, потом летает.
 

Ildarmustafin86

Active member
Нет, не использую. В нем не было необходимости. Но на перспективу придётся я думаю.
 

enjoynering

Well-known member
однако это вы зря. я ассихронные билиотеки не использую, все тольк из Arduino и пока не жалуюсь. сейчас у меня вот такой набор и скрость частично закешированной тяжелой страницы 1.2сек
 
Сверху Снизу