diff --git a/internal/webui/index.html b/internal/webui/index.html
index 9dd7666..64482dd 100644
--- a/internal/webui/index.html
+++ b/internal/webui/index.html
@@ -249,6 +249,8 @@
/** @type {{if_index:number,bridge_port:number,mac:string,learned_ip:string}[]} */
let lastPortDevItems = [];
let selectedFdbKey = null;
+ /** Увеличивается при каждом новом pollScanUntilDone — снимает гонку createScan vs watchScan (чередование строк статуса). */
+ let scanPollSeq = 0;
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
@@ -287,31 +289,47 @@
* @param {{ intervalMs?: number, maxWaitMs?: number, onDone?: function }} opts
*/
async function pollScanUntilDone(scanId, opts = {}) {
+ const mySeq = ++scanPollSeq;
const intervalMs = opts.intervalMs ?? 1000;
const maxWaitMs = opts.maxWaitMs ?? 20 * 60 * 1000;
const started = Date.now();
while (Date.now() - started < maxWaitMs) {
+ if (mySeq !== scanPollSeq) {
+ return null;
+ }
let job;
try {
job = await fetchScanJob(scanId);
} catch (e) {
- setStatus(`Ошибка опроса скана: ${e.message}`);
+ if (mySeq === scanPollSeq) {
+ setStatus(`Ошибка опроса скана: ${e.message}`);
+ }
+ return null;
+ }
+ if (mySeq !== scanPollSeq) {
return null;
}
setStatus(describeScanProgress(job));
if (job.status === "done" || job.status === "failed" || job.status === "canceled") {
+ if (mySeq !== scanPollSeq) {
+ return null;
+ }
if (opts.onDone) {
try {
await opts.onDone(job);
} catch (e) {
- setStatus((statusEl.textContent || "") + ` | Ошибка в onDone: ${e.message}`);
+ if (mySeq === scanPollSeq) {
+ setStatus((statusEl.textContent || "") + ` | Ошибка в onDone: ${e.message}`);
+ }
}
}
return job;
}
await sleep(intervalMs);
}
- setStatus(`Таймаут ожидания скана ${scanId} (${Math.round(maxWaitMs / 60000)} мин).`);
+ if (mySeq === scanPollSeq) {
+ setStatus(`Таймаут ожидания скана ${scanId} (${Math.round(maxWaitMs / 60000)} мин).`);
+ }
return null;
}