Ostatnio bawię się Workerami, rozpracowują uruchamianie pętli z możliwością jej przerwania. Nie chodzi o brutalne uwalenie wątku, tylko o to, że ja między iteracjami jest sprawdzenie, czy pętla ma się zakończyć, czy kontynuować (oczywiście z zachowaniem warunków pętli takich, jak liczba iteracji). Testuję na bardzo prostym przykładzie. Jest pętla, która ma 10 iteracji, każda iteracja trwa pół sekundy (wykonuje pustą pętlę z pomiarem czasu, ale jest to symulacja jakiejś długotrwałej operacji). Przycisk Start uruchamia proces, ale przycisk Break przerywa proces, oczywiście przerwanie następuje między iteracjami. Postęp pokazuje się w konsoli.
Opracowałem dwa warianty. Pierwszy wariant (nazwy zmiennych i funkcji od Worker1
) jest w stylu, w jakim stosuję w C# i C++ i tam działa z powodzeniem, a tutaj nie działa z tego powodu, że Worker podczas wykonywania funkcji nie jest w stanie natychmiast uruchomić innej funkcji. Drugi wariant (nazwy zmiennych i funkcji od Worker2
) działa tak, jakbym chciał, czyli przycisk Break
faktycznie zatrzymuje pętlę, ale jak widać kod jesst bardzo pokręcony.
Wystarczyłby jakikolwiek byt, który jest dostępny zarówno z Workera i z poza Workera i że jest to jeden i ten sam byt. Przekazywanie obiektów nie udało się, bo postMessage
zawsze kopiuje obiekt, a localStorage
ani sessionStorage
nie istnieje w Worker
. Czy da się i w jaki sposób poprawić pierwszy wariant, żeby można było przerwać pętlę, ale nie zagmatwać kodu tak, jak w drugim wariancie?
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<style type="text/css">
</style>
</head>
<body>
<input type="button" value="Start" onclick="Worker1Start()" />
<input type="button" value="Break" onclick="Worker1Break()" />
<br />
<input type="button" value="Start" onclick="Worker2Start()" />
<input type="button" value="Break" onclick="Worker2Break()" />
<script type="text/javascript">
function Worker1Def()
{
var Working;
this.onmessage = function(Evt)
{
switch (Evt.data.Cmd)
{
case 0:
{
Start();
}
return;
case 1:
{
Working = false;
console.log("Break");
}
}
}
function Start()
{
console.log("Start");
var I = 0;
Working = true;
while (Working)
{
console.log(I + " - begin");
var T = performance.now();
T = T + 500;
while (T > performance.now())
{
}
console.log(I + " - end");
I++;
if (I >= 10)
{
Working = false;
}
}
console.log("Stop");
}
}
var Worker1Obj = new Worker(URL.createObjectURL(new Blob(["("+Worker1Def.toString()+")()"], {type: 'text/javascript'})));
function Worker1Start()
{
Worker1Obj.postMessage({Cmd:0});
}
function Worker1Break()
{
Worker1Obj.postMessage({Cmd:1});
}
//////////////////////////////////////////////////////////////////////////////////////////////
function Worker2Def()
{
this.onmessage = function(Evt)
{
switch (Evt.data.Cmd)
{
case 0:
{
Start();
}
return;
case 1:
{
if (Evt.data.Val)
{
Loop();
}
else
{
console.log("Abort");
}
}
}
}
var LoopI;
function Start()
{
console.log("Start");
LoopI = 0;
Loop();
}
function Loop()
{
console.log(LoopI + " - begin");
var T = performance.now();
T = T + 500;
while (T > performance.now())
{
}
console.log(LoopI + " - end");
LoopI++;
if (LoopI < 10)
{
postMessage({Cmd:0})
}
else
{
console.log("Stop");
}
}
}
function Worker2DefCallback(Data)
{
Worker2Obj.postMessage({Cmd:1,Val:Worker2Working});
}
var Worker2Working;
var Worker2Obj = new Worker(URL.createObjectURL(new Blob(["("+Worker2Def.toString()+")()"], {type: 'text/javascript'})));
Worker2Obj.onmessage = Worker2DefCallback;
function Worker2Start()
{
Worker2Working = true;
Worker2Obj.postMessage({Cmd:0});
}
function Worker2Break()
{
Worker2Working = false;
}
</script>
</body>
</html>