
„Skrypt nie odpowiada”, „Przerwij działanie skryptu” i tym podobne irytujące komunikaty. W końcu JavaScript idealny nigdy nie był i pewnie nie będzie. Mimo wszystko jego obecne możliwości i poziom optymalizacji imponują. Dużym krokiem naprzód w stronę większych możliwości były HTML5 Web Workers. Wiąże się to z kwestiami wielowątkowości, z której możemy korzystać w JavaScript!
Popracujmy w JavaScipt z HTML5 web workers
Mówiąc najprościej, web workers umożliwiają nam przeniesienie ciężkiej pracy (skomplikowanych, czasochłonnych operacji) do wykonania w tle, bez zawieszania bieżącej aplikacji (strony). Jest to rodzaj wielowątkowości (threading) stworzony dla aplikacji Web.
W podejściu klasycznym ciężki kod JavaScript wykonywany będzie w pojedynczym wątku, na jednym rdzeniu. Więc nie skorzystamy z zalet naszego świetnego komputera z najnowszym wielordzeniowym procesorem.
Pójdźmy zatem w kierunku web workers, aby móc tworzyć coraz to bardziej wyrafinowane aplikacje, mogąc wykonywać jednocześnie wiele różnych wątków.
Podstawowe elementy na których opiera się praca z web workers:
Wywołanie worker’a
var worker = new Worker("my_task.js");
Wątki nie dzielą swoich stanów ze stroną ani nie mogą komunikować się między sobą bezpośrednio. Do tego celu służy funkcja postMessage()
worker.postMessage("Hello, Work!");
Potrzebna jest jeszcze obsługa zdarzenia
worker.onmessage = function(event) { alert("Received message " + event.data); // doSomething ... }
Działanie workera zakańczane jest funkcją terminate(), może być także wykonane wewnątrz kodu worker’a poprzez self.close(), co za chwilę zobaczymy w przykładzie.
Wczytywanie skryptów zewnętrznych umożliwia funkcja importScripts():
// my_task.js: importScripts('script1.js'); importScripts('script2.js'); // lub importScripts('script1.js', 'script2.js');
Przejdźmy teraz do uruchomienia workera w przykładowym kodzie.
Przykład implementacji
Tworzymy nowy plik HTML oraz skrypt my_task.js.
W pliku HTML umieszczamy podstawowe elementy:
... <button onclick="doHello()">Hello Command</button> <button onclick="doBye()">Bye Command</button> <button onclick="doDefault()">Unknown command</button> <button onclick="stop()">Stop the worker</button> <output id="result"></output> ...
A także kod JavaScript obsługujący wywołania naszego workera:
function doHello() { worker.postMessage({'cmd': 'start', 'msg': 'Hello'}); } function doBye() { worker.postMessage({'cmd': 'start', 'msg': 'Bye'}); } function doDefault() { worker.postMessage({'cmd': 'def', 'msg': 'Excuse me, what?'}); } function stop() { // worker.terminate(); worker.postMessage({'cmd': 'stop', 'msg': 'STOP'}); } // GO var worker = new Worker('my_task.js'); worker.addEventListener('message', function(e) { document.getElementById('result').textContent = e.data; }, false);
Przejdźmy teraz do pliku my_task.js i dodajmy kod JavaScript, rozpoczynając od self.addEventListener:
self.addEventListener('message', function(e) { var data = e.data; switch (data.cmd) { // process "start" command case 'start': self.postMessage('WORKER STARTED: ' + data.msg); break; case 'stop': self.postMessage('WORKER STOPPED: ' + data.msg + '(off)'); self.close(); // terminate the worker break; default: self.postMessage('Unknown command: ' + data.msg); }; }, false);
Stworzyliśmy event listener obsługujący wywołania naszego workera, oraz przykładowy kod reagujący na przesłane komendy.
W taki sposób możemy tworzyć wiele skomplikowanych wątków, pracujących w tle, bez obaw o zawieszanie się strony.
Demo do uruchomienia tutaj, natomiast kod do pobrania:
http://directcode.eu/samples/web_workers/web_workers.zip
Zasoby
Wpierw wspomnę o badaniu dostępności obsługi interesującej nas funkcjonalności.
Modernizr to biblioteka znana z poprzednich wpisów, wspomaga także sprawdzanie dostępności web workers w przeglądarce.
Przykład:
if (Modernizr.webworkers) { // window.Worker is available! } // or function supports_web_workers() { return !!window.Worker; }
Ciekawsze przykłady zastosowań HTML5 web workers, takich jak generowanie fraktali na HTML5 Canvas:
http://simpledeveloper.com/mandelbrot/
To świetny przykład kodu.
Zasoby dla dociekliwych:
– From scratch
http://www.html5rocks.com/en/tutorials/workers/basics/
– MDN
https://developer.mozilla.org/pl/docs/Web/Guide/Performance/Uzycie_web_workers
– wiele różnorodnych, ciekawych przykładów zastosowań HTML5 Web Workers
http://www.whatwg.org/specs/web-apps/current-work/multipage/workers.html
Podsumowanie
HTML5 Web Workers to z pewnością interesujące rozszerzenie możliwości dostępnych w języku JavaScript. Powoli lecz systematycznie, dostępne z poziomu aplikacji Web staje się wszystko to, co do niedawna możliwe było jedynie w programowaniu na niższych warstwach abstrakcji.
Dziękuję za uwagę.