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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
|
---
title: Использование Web Workers
slug: DOM/Using_web_workers
tags:
- воркер
- поток
translation_of: Web/API/Web_Workers_API/Using_web_workers
---
<div>{{DefaultAPISidebar("Web Workers API")}}</div>
<p>Web Worker-ы предоставляют простое средство для запуска скриптов в фоновом потоке. Поток Worker'а может выполнять задачи без вмешательства в пользовательский интерфейс. К тому же, они могут осуществлять ввод/вывод, используя <code><a class="internal" href="/en-US/docs/Mozilla/Tech/XPCOM/Reference/Interface/nsIXMLHttpRequest">XMLHttpRequest</a></code> (хотя атрибуты <code>responseXML</code> и <code>channel</code> всегда будут равны null). Существующий Worker может отсылать сообщения JavaScript коду-создателю через обработчик событий, указанный этим кодом (и наоборот). Эта статья дает детальную инструкцию по использованию Web Workers.</p>
<h2 id="Web_Workers_API">Web Workers API</h2>
<p>Worker - это объект, создаваемый конструктором (например, {{domxref("Worker.Worker", "Worker()")}}) и запускающий именной JavaScript файл — этот файл содержит код, который будет выполнен в потоке Worker'а; объекты же Workers запускаются в другом глобальном контексте, отличающемся от текущего, - {{domxref("window")}}. Поэтому использование переменной {{domxref("window")}} для получения текущего глобального контекста (вместо {{domxref("window.self","self")}}) внутри {{domxref("Worker")}} вернет ошибку.</p>
<p>Контекст Worker'а представлен объектом {{domxref("DedicatedWorkerGlobalScope")}} в случае выделенных Workers (обычные Workers используются одним скриптом; совместные Workers используют объект {{domxref("SharedWorkerGlobalScope")}}). Выделенный Worker доступен только из скрипта-родителя, в то время как совместные Workers могут быть доступны из нескольких сценариев.</p>
<div class="note">
<p><strong>Заметка</strong>: Смотрите <a href="/en-US/docs/Web/API/Web_Workers_API">страницу Web Workers API</a> для справки по Workers и прочие руководства.</p>
</div>
<p>Вы можете запускать любой код внутри потока worker-а, за некоторыми исключениями. Например, вы не можете прямо манипулировать DOM внутри worker-а, или использовать некоторые методы по умолчанию и свойства объекта {{domxref("window")}}. Но вы можете использовать большой набор опций, доступный под <code>Window</code>, включая <a href="/en-US/docs/Web/API/WebSockets_API">WebSockets</a>, и механизмы хранения данных, таких как <a href="/en-US/docs/Web/API/IndexedDB_API">IndexedDB</a> и относящихся только к Firefox OS <a href="/en-US/docs/Web/API/Data_Store_API">Data Store API</a>. Для дополнительной информации смотрите <a href="/en-US/docs/Web/API/Worker/Functions_and_classes_available_to_workers">Functions and classes available to workers</a>.</p>
<p>Данные передаются между worker-ами и главным потоком через систему сообщений — обе стороны передают свои сообщения, используя метод <code>postMessage()</code> и отвечают на сообщения при помощи обработчика событий <code>onmessage</code> (сообщение хранится в аттрибуте data события {{event("Message")}}). Данные при этом копируются, а не делятся.</p>
<p>Объекты Workers могут, в свою очередь, создавать новые объекты workers, и так до тех пор, пока всё работает в рамках текущей страницы. Плюс к этому, объекты workers могут использовать <a class="internal" href="/en-US/docs/Web/API/XMLHttpRequest"><code>XMLHttpRequest</code></a> для сетевого ввода/вывода, но есть исключение - атрибуты <code>responseXML</code> и <code>channel</code> объекта <code>XMLHttpRequest</code> всегда возвращают <code>null</code>.</p>
<h2 id="Выделенные_Workers">Выделенные Workers</h2>
<p>Как уже упоминалось выше, выделенный Worker доступен только для скрипта, который его вызвал. В этом разделе речь пойдет о JavaScript, который можно найти в нашем <a class="external external-icon" href="https://github.com/mdn/simple-web-worker">основном примере выделенного Worker</a> (<a class="external external-icon" href="http://mdn.github.io/simple-web-worker/">запустить скрипт</a>): этот пример позволяет ввести два числа для умножения. Эти числа отправляются в Worker, перемножаются, а результат возвращается на страницу и отображается.</p>
<p>Этот пример достаточно тривиален, но для ознакомления с базовыми концепциями worker-ов мы решили его упростить. Более продвинутые детали описаны далее в статье.</p>
<h3 id="Определение_поддержки_Worker">Определение поддержки Worker</h3>
<p>Для большего контроля над ошибками и обратной совместимости, рекомендуется обернуть ваш код доступа к worker-у в следующий (<a href="https://github.com/mdn/simple-web-worker/blob/gh-pages/main.js">main.js</a>):</p>
<pre class="brush: js notranslate">if (window.Worker) {
...
}</pre>
<h3 id="Создание_выделенного_worker">Создание выделенного worker</h3>
<p>Создание нового worker-а — это легко. Всё что вам нужно это вызвать конструктор {{domxref("Worker.Worker", "Worker()")}}, указав URI скрипта для выполнения в потоке worker-а (<a href="https://github.com/mdn/simple-web-worker/blob/gh-pages/main.js">main.js</a>):</p>
<div style="overflow: hidden;">
<pre class="brush: js notranslate">var myWorker = new Worker("worker.js");
</pre>
</div>
<h3 id="Передача_сообщений_в_и_из_выделенного_worker">Передача сообщений в и из выделенного worker</h3>
<p>Магия worker-ов происходит через {{domxref("Worker.postMessage", "postMessage()")}} метод и обработчик событий {{domxref("Worker.onmessage", "onmessage")}}. Когда вы хотите отправить сообщение в worker, вы доставляете сообщение к нему вот так (<a href="https://github.com/mdn/simple-web-worker/blob/gh-pages/main.js">main.js</a>):</p>
<pre class="brush: js notranslate">first.onchange = function() {
myWorker.postMessage([first.value,second.value]);
console.log('Message posted to worker');
}
second.onchange = function() {
myWorker.postMessage([first.value,second.value]);
console.log('Message posted to worker');
}</pre>
<p>В приведенном фрагменте кода мы имеем два {{htmlelement("input")}} элемента, представленных переменными <code>first</code> и <code>second</code>; когда значение любой из переменных изменяется,<code> myWorker.postMessage([first.value,second.value])</code> используется для отправки обоих значений, представленных в виде массива, в worker. Посредством аргумента <code>message</code> возможна передача практически любых данных в worker.</p>
<p>Внутри worker-a мы можем обрабатывать сообщения и отвечать на них при помощи добавления обработчика события <code>onmessage</code> подобным образом (<a href="https://github.com/mdn/simple-web-worker/blob/gh-pages/worker.js">worker.js</a>):</p>
<pre class="brush: js notranslate">onmessage = function(e) {
console.log('Message received from main script');
var workerResult = 'Result: ' + (e.data[0] * e.data[1]);
console.log('Posting message back to main script');
postMessage(workerResult);
}</pre>
<p>Обработчик <code>onmessage</code> позволяет нам запустить некий код всякий раз, когда получен пакет с сообщением, доступным в атрибуте <code>data</code> события <code>message</code>. В примере выше мы просто перемножаем вместе две цифры, после чего используем <code>postMessage()</code> снова, чтобы отправить полученный результат назад в основной поток.</p>
<p>Возвращаясь в основной поток, мы используем <code>onmessage</code> снова, чтобы отреагировать на сообщение, отправленное нам назад из worker-а:</p>
<pre class="brush: js notranslate">myWorker.onmessage = function(e) {
result.textContent = e.data;
console.log('Message received from worker');
}</pre>
<p>В примере выше мы берём данные из события сообщения и ставим их как <code>textContent</code> у результирующего абзаца, чтобы показать пользователю результат этой калькуляции.</p>
<p class="note"><strong>Заметка</strong>: Обратите внимание, что <font face="consolas, Liberation Mono, courier, monospace"><code>onmessage()</code> и <code>postmessage()</code> должны вызываться из экземпляра Worker в главном потоке, но не в потоке worker-а. Это связано с тем, что внутри потока worker-а, worker выступает в качестве глобального объекта.</font></p>
<p class="note"><strong>Заметка</strong>: При передаче сообщения между основным потоком и потоком worker-а, оно копируется или "передается" (перемещается), не делится между потоками. Читайте {{anch("Transferring data to and from workers: further details")}} для более подробного объяснения.</p>
<h3 id="Завершение_работы_worker-а">Завершение работы worker-а</h3>
<p>Прекращение работы worker-а главного потока достигается методом {{domxref("Worker", "terminate")}}:</p>
<pre class="brush: js notranslate">myWorker.terminate();</pre>
<p>Поток worker-а немедленно уничтожается.</p>
<h3 id="Обработка_ошибок">Обработка ошибок</h3>
<p>При ошибке во время выполнения worker-а, вызывается его обработчик событий <code>onerror</code>. Он принимает событие <code>error</code>, которое реализует интерфейс <code>ErrorEvent</code>.</p>
<p>Событие не всплывает и его можно отменить. Для отмены действия по умолчанию, worker может вызвать метод <a class="internal" href="/en-US/docs/Web/API/Event/preventDefault"> <code>preventDefault()</code> </a> в обработчике события ошибки.</p>
<p>У события ошибки есть три поля, которые представляют интерес:</p>
<dl>
<dt><code>message</code></dt>
<dd>Сообщение об ошибке в читаемом виде.</dd>
<dt><code>filename</code></dt>
<dd>Имя файла со скриптом, в котором ошибка произошла.</dd>
<dt><code>lineno</code></dt>
<dd>Номер строки в файле, в котором произошла ошибка.</dd>
</dl>
<h3 id="Создание_subworkers">Создание subworkers</h3>
<p>Worker-ы могут запускать другие worker-ы. Так называемые sub-worker'ы должны быть того же происхождения (same-origin), что и родительский документ. Кроме того, URI для subworker-ов рассчитываются относительно родительского worker'а, а не родительского документа. Это позволяет worker-ам проще следить за тем, где находятся их зависимости.</p>
<h3 id="Импорт_скриптов_и_библиотек">Импорт скриптов и библиотек</h3>
<p>Worker потоки имеют доступ к глобальной функции, <code>importScripts()</code>, которая позволяет импортировать скрипты с того же домена в их область видимости. Функция принимает ноль и более URI параметров, как список ссылок на ресурсы для импорта; все нижеприведенные примеры верны:</p>
<pre class="brush: js notranslate">importScripts(); /* imports nothing */
importScripts('foo.js'); /* imports just "foo.js" */
importScripts('foo.js', 'bar.js'); /* imports two scripts */
</pre>
<p>Браузер загружает каждый указанный скрипт и исполняет его. Любые глобальные объекты, создаваемые каждым скриптом могут быть использованы в worker'е. Если скрипт не удалось загрузить, будет брошена ошибка <code>NETWORK_ERROR</code>, и последующий код не будет исполнен. Тем не менее код, исполненный ранее (включая отложенный при помощи {{domxref("window.setTimeout()")}}) останется функционален. Объявления функций идущие <strong>после</strong> вызова метода <code>importScripts()</code> также будут доступны, т.к. объявления функций всегда обрабатываются перед остальным кодом.</p>
<div class="note"><strong>Заметка</strong>: Скрипты могут быть загружены в произвольном порядке, но их исполнение будет в том порядке, в котором имена файлов были переданы в <code>importScripts()</code>. Функция выполняется синхронно; <code>importScripts()</code> не вернет исполнение, пока все скрипты не будут загружены и исполнены.</div>
<h2 id="Разделяемые_worker-ы_Shared_workers">Разделяемые worker-ы (Shared workers)</h2>
<p>Разделяемый worker доступен нескольким разным скриптам — даже если они находятся в разных окнах, фреймах или даже worker-ах. В этом разделе мы обсудим JavaScript, который можно найти в нашем <a class="external external-icon" href="https://github.com/mdn/simple-shared-worker">базовом примере разделяемых worker-ов</a> (<a class="external external-icon" href="http://mdn.github.io/simple-shared-worker/">запустить разделяемый worker</a>): Он очень похож на базовый пример выделенных worker-ов, за исключением двух функций, которые доступны из разных скриптовых файлов: <em>умножение двух чисел</em> или <em>возведение числа в степень.</em> Оба скрипта используют один и тот же worker для необходимых вычислений.</p>
<p>Здесь мы сосредоточимся на разнице между выделенными и раздялемыми worker-ами. Обратите внимание, что в данном примере есть две HTML страницы с JavaScript кодом, которые используют один и тот же файл worker-а.</p>
<div class="note">
<p><strong>Заметка</strong>: Если разделяемый worker может быть доступен из нескольких контекстов просмотра, то все они должны иметь одно и то же происхождение (одни и те же протокол, хост и порт).</p>
</div>
<div class="note">
<p><strong>Заметка: </strong>В Firefox разделяемый worker не может быть использован совместно документами в приватном и неприватном окне ({{bug(1177621)}}).</p>
</div>
<h3 id="Создание_разделяемого_worker-а">Создание разделяемого worker-а</h3>
<p>Запуск разделяемого worker-а очень похож на запуск выделенного worker-а, но используется другой конструктор (см. <a href="https://github.com/mdn/simple-shared-worker/blob/gh-pages/index.html">index.html</a> и <a href="http://mdn.github.io/simple-shared-worker/index2.html">index2.html</a>) — в каждом документе необходимо поднять worker, для этого следует написать такой код:</p>
<pre class="brush: js notranslate">var myWorker = new SharedWorker("worker.js");</pre>
<p>Большая разница заключается в том, что с разделяемым worker-ом необходимо взаимодействовать через объект <code>port</code> — явно открыв порт, с помощью которого скрипты могут взаимодействовать с worker-ом (в случае выделенного worker-а это происходит неявно).</p>
<p>Соединение с портом должно быть осуществлено либо неявно, используя обработчик событие <code>onmessage</code>, либо явно, вызвав метод <strong>start()</strong> перед тем, как отправлять любые сообщения. Вызов метода start() необходим только тогда, когда подписка на событие реализована через метод <code>addEventListener()</code>.</p>
<div class="blockIndicator note">
<p><strong>Заметка: </strong>Когда используется метод <code>start()</code> чтобы открыть соединение с портом, его необходимо вызывать и в родительском потоке и в потоке worker-а, если необходима двухсторонняя коммуникация.</p>
</div>
<pre class="brush: js notranslate">myWorker.port.start(); // в родительском потоке</pre>
<pre class="brush: js notranslate">port.start(); // в потоке worker-а, где переменная <code>port</code> является ссылкой на порт</pre>
<h3 id="Передача_сообщений_виз_разделяемого_worker-а">Передача сообщений в/из разделяемого worker-а</h3>
<p>Теперь сообщения могут быть отправлены worker-у, как и прежде, но метод <code>postMessage()</code> должен вызываться из объекта <code>port</code> (еще раз, вы можете увидеть схожие кострукции в <a href="https://github.com/mdn/simple-shared-worker/blob/gh-pages/multiply.js">multiply.js</a> и <a href="https://github.com/mdn/simple-shared-worker/blob/gh-pages/square.js">square.js</a>):</p>
<pre class="brush: js notranslate">squareNumber.onchange = function() {
myWorker.port.postMessage([squareNumber.value,squareNumber.value]);
console.log('Message posted to worker');
}</pre>
<p>Теперь на стороне worker-а. Здесь код немного сложнее (<a href="https://github.com/mdn/simple-shared-worker/blob/gh-pages/worker.js">worker.js</a>):</p>
<pre class="brush: js notranslate">self.addEventListener('connect', function(e) { // требуется addEventListener()
var port = e.ports[0];
port.onmessage = function(e) {
var workerResult = 'Result: ' + (e.data[0] * e.data[1]);
port.postMessage(workerResult);
}
<s>port.start();</s> // вызов необязательный, т.к. используется обработчик событий onmessage
});</pre>
<p>Первый этап состоит из события <code>onconnect</code>. Оно срабатывает, когда произошло подключение (т.е. когда в родительском потоке отработало событие <code>onmessage</code> или когда в нем был вызван метод <code>start()</code>).</p>
<p>Мы используем атрибут события <code>ports</code>, чтобы получить порт и сохранить его в переменной.</p>
<p>Второй этап — это обработчик события <code>message</code> на сохраненном порту. Он нужен для подсчета и вывода результата вычисления в основной поток. Установка обработчика <code>message</code> в потоке worker-а также открывает подключение к родительскому потоку, поэтому вызов на <code>port.start()</code> на самом деле не нужен (см. код обработчика <code>onconnect</code>).</p>
<p>Последний этап — возвращение в основной поток и обработка сообщения от worker‑а (еще раз, вы можете увидеть схожие конструкции в <a href="https://github.com/mdn/simple-shared-worker/blob/gh-pages/multiply.js">multiply.js</a> и <a href="https://github.com/mdn/simple-shared-worker/blob/gh-pages/square.js">square.js</a>):</p>
<pre class="brush: js notranslate">myWorker.port.onmessage = function(e) {
result2.textContent = e.data[0];
console.log('Message received from worker');
}</pre>
<p>Когда сообщение приходит через порт от worker-а, мы проверяем тип результата вычислений и затем вставляем его в соответствующий абзац.</p>
<h2 id="О_потоковой_безопасности">О потоковой безопасности</h2>
<p>Интерфейс {{domxref("Worker")}} создаёт настоящие потоки на уровне операционной системы, что может смутить опытных программистов и навести их на мысли о проблемах, связанных с конфликтом доступа к общим объектам.</p>
<p>На самом деле создать такие проблемы достаточно сложно, так как worker-ы жёстко контролируются. У них нет доступа к непотокобезопасным объектам DOM, а все данные между потоками передаются в качестве сериализованных объектов. Придётся очень постараться, чтобы вызывать проблемы потокобезопасности в вашем коде.</p>
<h2 id="Передача_данных_в_и_из_worker-ов_другие_детали">Передача данных в и из worker-ов: другие детали</h2>
<p>Передача данных между главной страницей и worker-ом происходит путем копирования, а не передачи по ссылке. Объекты сериализуются при передаче и затем десериализуются на другом конце. Страница и worker не используют совместно одни и те же экземпляры, для каждого создается свой. Большинство браузеров реализуют это структурированным клонированием (<a href="/en-US/docs/Web/Guide/API/DOM/The_structured_clone_algorithm">structured cloning</a>).</p>
<p>Для иллюстрации этого мы создадим функцию <code>emulateMessage()</code>, которая будет имитировать поведение значения, которое клонируется, но не используется совместно при переходе от worker-а к главной странице или наоборот.</p>
<pre class="brush: js notranslate">function emulateMessage (vVal) {
return eval("(" + JSON.stringify(vVal) + ")");
}
// Tests
// test #1
var example1 = new Number(3);
console.log(typeof example1); // object
console.log(typeof emulateMessage(example1)); // number
// test #2
var example2 = true;
console.log(typeof example2); // boolean
console.log(typeof emulateMessage(example2)); // boolean
// test #3
var example3 = new String("Hello World");
console.log(typeof example3); // object
console.log(typeof emulateMessage(example3)); // string
// test #4
var example4 = {
"name": "John Smith",
"age": 43
};
console.log(typeof example4); // object
console.log(typeof emulateMessage(example4)); // object
// test #5
function Animal (sType, nAge) {
this.type = sType;
this.age = nAge;
}
var example5 = new Animal("Cat", 3);
alert(example5.constructor); // Animal
alert(emulateMessage(example5).constructor); // Object</pre>
<p>Значения, которые клонируются и совместно не используются, называются сообщениями. Как вы, возможно, знаете, сообщения могут быть отправлены в главную страницу и из нее, используя <code>postMessage()</code>, и {{domxref("MessageEvent.data", "data")}}, содержа данные, передаваемые из worker-а.</p>
<p><strong>example.html</strong>: (главная страница):</p>
<pre class="brush: js notranslate">var myWorker = new Worker("my_task.js");
myWorker.onmessage = function (oEvent) {
console.log("Worker said : " + oEvent.data);
};
myWorker.postMessage("ali");</pre>
<p><strong>my_task.js</strong> (worker):</p>
<pre class="brush: js notranslate">postMessage("I\'m working before postMessage(\'ali\').");
onmessage = function (oEvent) {
postMessage("Hi " + oEvent.data);
};</pre>
<p>Алгоритм структурированного клонирования может принять JSON и некоторые вещи, которые JSON не может принять, например, циклические ссылки.</p>
<h3 id="Примеры_передачи_данных">Примеры передачи данных</h3>
<h4 id="Пример_1_Расширенная_передача_JSON_данных_и_создание_системы_коммутации">Пример #1: Расширенная передача JSON данных и создание системы коммутации</h4>
<p>Если вам нужно передать сложные данные и вызвать множество различных функций как на главной странице, так и в worker-е, вы можете создать следующую систему.</p>
<p>В первую очередь мы создаем класс QueryableWorker, который принимает url worker-а, стандартный обработчик событий (defaultListener) и обработчик ошибок. Этот класс будет отслеживать всех обработчиков и поможет нам общаться с воркером.</p>
<pre class="brush: js notranslate"><code>function QueryableWorker(url, defaultListener, onError) {
var instance = this,
worker = new Worker(url),
listeners = {};
this.defaultListener = defaultListener || function() {};
if (onError) {worker.onerror = onError;}
this.postMessage = function(message) {
worker.postMessage(message);
}
this.terminate = function() {
worker.terminate();
}
}</code>
</pre>
<p>Затем мы добавляем методы добавления/удаления обработчиков.</p>
<pre class="brush: js notranslate"><code>this.addListeners = function(name, listener) {
listeners[name] = listener;
}
this.removeListeners = function(name) {
delete listeners[name];
}</code>
</pre>
<p>Здесь мы создадим у worker-а два простых события для примера: получение разницы двух чисел и создание оповещения через три секунды. Но сначала нам нужно реализовать метод sendQuery, который проверит есть ли вообще у worker-а обработчик, который мы собираемся вызвать.</p>
<pre class="brush: js notranslate"><code>/*
Эта функция принимает по крайней мере один аргумент: имя метода, который мы хотим вызвать.
Далее мы можем передать методу необходимые ему аргументы.
*/
this.sendQuery = function() {
if (arguments.length < 1) {
throw new TypeError('QueryableWorker.sendQuery takes at least one argument');
return;
}
worker.postMessage({
'queryMethod': arguments[0],
'queryArguments': Array.prototype.slice.call(arguments, 1)
});
}</code>
</pre>
<p>Завершим QueryableWorker методом <code>onmessage</code>. Если worker имеет соответствующий метод, который мы запросили, он также должен вернуть соответствующий обработчик и аргументы, которые нам нужны. Останется лишь найти его в <code>listeners</code>:</p>
<pre class="brush: js notranslate"><code>worker.onmessage = function(event) {
if (event.data instanceof Object &&
event.data.hasOwnProperty('queryMethodListener') &&
event.data.hasOwnProperty('queryMethodArguments')) {
listeners[event.data.queryMethodListener].apply(instance, event.data.queryMethodArguments);
} else {
this.defaultListener.call(instance, event.data);
}
}</code>
</pre>
<p>Теперь к самому worker-у. Сначала следует определить эти два простых метода:</p>
<pre class="brush: js notranslate"><code>var queryableFunctions = {
getDifference: function(a, b) {
reply('printStuff', a - b);
},
waitSomeTime: function() {
setTimeout(function() {
reply('doAlert', 3, 'seconds');
}, 3000);
}
}
function reply() {
if (arguments.length < 1) {
throw new TypeError('reply - takes at least one argument');
return;
}
postMessage({
queryMethodListener: arguments[0],
queryMethodArguments: Array.prototype.slice.call(arguments, 1)
});
}
/* This method is called when main page calls QueryWorker's postMessage method directly*/
function defaultReply(message) {
// do something
}</code>
</pre>
<p>И <code>onmessage</code>:</p>
<pre class="brush: js notranslate"><code>onmessage = function(event) {
if (event.data instanceof Object &&
event.data.hasOwnProperty('queryMethod') &&
event.data.hasOwnProperty('queryMethodArguments')) {
queryableFunctions[event.data.queryMethod]
.apply(self, event.data.queryMethodArguments);
} else {
defaultReply(event.data);
}
}</code></pre>
<p>Полный код примера:</p>
<p><strong>example.html</strong> (основная страница):</p>
<pre class="brush: html notranslate"><code><!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>MDN Example - Queryable worker</title>
<script type="text/javascript">
/*
QueryableWorker instances methods:
* sendQuery(queryable function name, argument to pass 1, argument to pass 2, etc. etc): calls a Worker's queryable function
* postMessage(string or JSON Data): see Worker.prototype.postMessage()
* terminate(): terminates the Worker
* addListener(name, function): adds a listener
* removeListener(name): removes a listener
QueryableWorker instances properties:
* defaultListener: the default listener executed only when the Worker calls the postMessage() function directly
*/
function QueryableWorker(url, defaultListener, onError) {
var instance = this,
worker = new Worker(url),
listeners = {};
this.defaultListener = defaultListener || function() {};
if (onError) {worker.onerror = onError;}
this.postMessage = function(message) {
worker.postMessage(message);
}
this.terminate = function() {
worker.terminate();
}
this.addListener = function(name, listener) {
listeners[name] = listener;
}
this.removeListener = function(name) {
delete listeners[name];
}
/*
This functions takes at least one argument, the method name we want to query.
Then we can pass in the arguments that the method needs.
*/
this.sendQuery = function() {
if (arguments.length < 1) {
throw new TypeError('QueryableWorker.sendQuery takes at least one argument');
return;
}
worker.postMessage({
'queryMethod': arguments[0],
'queryMethodArguments': Array.prototype.slice.call(arguments, 1)
});
}
worker.onmessage = function(event) {
if (event.data instanceof Object &&
event.data.hasOwnProperty('queryMethodListener') &&
event.data.hasOwnProperty('queryMethodArguments')) {
listeners[event.data.queryMethodListener].apply(instance, event.data.queryMethodArguments);
} else {
this.defaultListener.call(instance, event.data);
}
}
}
// your custom "queryable" worker
var myTask = new QueryableWorker('my_task.js');
// your custom "listeners"
myTask.addListener('printStuff', function (result) {
document.getElementById('firstLink').parentNode.appendChild(document.createTextNode('The difference is ' + result + '!'));
});
myTask.addListener('doAlert', function (time, unit) {
alert('Worker waited for ' + time + ' ' + unit + ' :-)');
});
</script>
</head>
<body>
<ul>
<li><a id="firstLink" href="javascript:myTask.sendQuery('getDifference', 5, 3);">What is the difference between 5 and 3?</a></li>
<li><a href="javascript:myTask.sendQuery('waitSomeTime');">Wait 3 seconds</a></li>
<li><a href="javascript:myTask.terminate();">terminate() the Worker</a></li>
</ul>
</body>
</html></code></pre>
<p><strong>my_task.js</strong> (код worker-а):</p>
<pre class="brush: js notranslate"><code>var queryableFunctions = {
// пример #1: получить разницу между двумя числами
getDifference: function(nMinuend, nSubtrahend) {
reply('printStuff', nMinuend - nSubtrahend);
},
// пример #2: подождать три секунды
waitSomeTime: function() {
setTimeout(function() { reply('doAlert', 3, 'seconds'); }, 3000);
}
};
// системные функции
function defaultReply(message) {
// your default PUBLIC function executed only when main page calls the queryableWorker.postMessage() method directly
// do something
}
function reply() {
if (arguments.length < 1) { throw new TypeError('reply - not enough arguments'); return; }
postMessage({ 'queryMethodListener': arguments[0], 'queryMethodArguments': Array.prototype.slice.call(arguments, 1) });
}
onmessage = function(oEvent) {
if (oEvent.data instanceof Object && oEvent.data.hasOwnProperty('queryMethod') && oEvent.data.hasOwnProperty('queryMethodArguments')) {
queryableFunctions[oEvent.data.queryMethod].apply(self, oEvent.data.queryMethodArguments);
} else {
defaultReply(oEvent.data);
}
};</code>
</pre>
<p>Можно переключать содержимое каждой главной страницы -> worker и worker -> сообщение главной страницы. И имена свойств "queryMethod", "queryMethodListeners", "queryMethodArguments" могут быть любыми пока они согласуются с <code>QueryableWorker</code> и <code>worker</code>.</p>
<h3 id="Передача_данных_с_помощью_передачи_владения_передаваемые_объекты">Передача данных с помощью передачи владения (передаваемые объекты)</h3>
<p>Google Chrome 17+ and Firefox 18+ имеют дополнительную возможность передачи определенных типов объектов (передаваемые объекты реализующие {{domxref("Transferable")}} интерфейс) к или из worker-а с высокой призводительностью. Эти объекты передаются из одного контекста в другой без операций копирования, что приводит к значительному повышению производительности при отправке больших наборов данных. Думайте об этом как о передаче по ссылке в мире C/C++. Однако в отличии от передачи по ссылке, "версия" из вызывающего контекста больше недоступна после передачи. Владельцем становится новый контекст. Для примера, после передачи {{domxref("ArrayBuffer")}} из главной страницы к worker-у, исходный {{domxref("ArrayBuffer")}} очищается и более недоступен для использования. Его содержание (в буквальном смысле) переносится в рабочий контекст.</p>
<pre class="brush: js notranslate">// Create a 32MB "file" and fill it.
var uInt8Array = new Uint8Array(1024*1024*32); // 32MB
for (var i = 0; i < uInt8Array.length; ++i) {
uInt8Array[i] = i;
}
worker.postMessage(uInt8Array.buffer, [uInt8Array.buffer]);
</pre>
<div class="note">
<p><strong>Заметка</strong>: Для дополнительной информации о передаваемых объектах, производительности и поддержки для этого метода, читайте <a href="http://updates.html5rocks.com/2011/12/Transferable-Objects-Lightning-Fast">Transferable Objects: Lightning Fast!</a> на HTML5 Rocks.</p>
</div>
<h2 id="Встроенные_worker-ы">Встроенные worker-ы</h2>
<p>Не существует утвержденного способа встроить код worker-а в рамках веб-страницы, как элемент {{HTMLElement("script")}} делает для обычных скриптов. Но элемент {{HTMLElement("script")}}, который не имеет аттрибута <code>src</code> и аттрибута <code>type</code>, которому не назначен выполняемый MIME type, можно считать блоком данных для использования JavaScript. Блок данных "Data blocks" — это более общее свойство HTML5, может содержать любые текстовые данные. Так, worker может быть встроен следующим образом:</p>
<pre class="brush: html line-numbers language-html notranslate"><code class="language-html"><span class="doctype token"><!DOCTYPE html></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>html</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>head</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>meta</span> <span class="attr-name token">charset</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>UTF-8<span class="punctuation token">"</span></span> <span class="punctuation token">/></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>title</span><span class="punctuation token">></span></span>MDN Example - Embedded worker<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>title</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>script</span> <span class="attr-name token">type</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>text/js-worker<span class="punctuation token">"</span></span><span class="punctuation token">></span></span><span class="script token"><span class="language-javascript token">
<span class="comment token">// Этот script НЕ БУДЕТ анализироваться JS движками, потому что его MIME-тип text/js-worker.</span>
<span class="keyword token">var</span> myVar <span class="operator token">=</span> <span class="string token">'Hello World!'</span><span class="punctuation token">;</span>
<span class="comment token">// </span></span></span></code>Остальная часть кода вашего воркера идет сюда.<code class="language-html"><span class="script token"><span class="language-javascript token">
</span></span><span class="tag token"><span class="tag token"><span class="punctuation token"></</span>script</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>script</span> <span class="attr-name token">type</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>text/javascript<span class="punctuation token">"</span></span><span class="punctuation token">></span></span><span class="script token"><span class="language-javascript token">
<span class="comment token">// Этот script БУДЕТ проанализирован JS движкам, потому что его MIME-тип text/javascript.</span>
<span class="keyword token">function</span> <span class="function token">pageLog</span><span class="punctuation token">(</span><span class="parameter token">sMsg</span><span class="punctuation token">)</span> <span class="punctuation token">{</span>
<span class="comment token">// Use a fragment: browser will only render/reflow once.</span>
<span class="keyword token">var</span> oFragm <span class="operator token">=</span> document<span class="punctuation token">.</span><span class="function token">createDocumentFragment</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
oFragm<span class="punctuation token">.</span><span class="function token">appendChild</span><span class="punctuation token">(</span>document<span class="punctuation token">.</span><span class="function token">createTextNode</span><span class="punctuation token">(</span>sMsg<span class="punctuation token">)</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
oFragm<span class="punctuation token">.</span><span class="function token">appendChild</span><span class="punctuation token">(</span>document<span class="punctuation token">.</span><span class="function token">createElement</span><span class="punctuation token">(</span><span class="string token">'br'</span><span class="punctuation token">)</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
document<span class="punctuation token">.</span><span class="function token">querySelector</span><span class="punctuation token">(</span><span class="string token">'#logDisplay'</span><span class="punctuation token">)</span><span class="punctuation token">.</span><span class="function token">appendChild</span><span class="punctuation token">(</span>oFragm<span class="punctuation token">)</span><span class="punctuation token">;</span>
<span class="punctuation token">}</span>
</span></span><span class="tag token"><span class="tag token"><span class="punctuation token"></</span>script</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>script</span> <span class="attr-name token">type</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>text/js-worker<span class="punctuation token">"</span></span><span class="punctuation token">></span></span><span class="script token"><span class="language-javascript token">
<span class="comment token">// Этот script НЕ БУДЕТ анализироваться JS движками, потому что его MIME-тип text/js-worker.</span>
<span class="function function-variable token">onmessage</span> <span class="operator token">=</span> <span class="keyword token">function</span><span class="punctuation token">(</span><span class="parameter token">oEvent</span><span class="punctuation token">)</span> <span class="punctuation token">{</span>
<span class="function token">postMessage</span><span class="punctuation token">(</span>myVar<span class="punctuation token">)</span><span class="punctuation token">;</span>
<span class="punctuation token">}</span><span class="punctuation token">;</span>
<span class="comment token">// </span></span></span></code>Остальная часть кода вашего воркера идет сюда.<code class="language-html"><span class="script token"><span class="language-javascript token">
</span></span><span class="tag token"><span class="tag token"><span class="punctuation token"></</span>script</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>script</span> <span class="attr-name token">type</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>text/javascript<span class="punctuation token">"</span></span><span class="punctuation token">></span></span><span class="script token"><span class="language-javascript token">
<span class="comment token">// Этот script БУДЕТ проанализирован JS движкам, потому что его MIME-тип text/javascript.</span>
<span class="comment token">// В прошлом...:</span>
<span class="comment token">// blob builder существовал</span>
<span class="comment token">// ... но теперь мы используем Blob...:</span>
<span class="keyword token">var</span> blob <span class="operator token">=</span> <span class="keyword token">new</span> <span class="class-name token">Blob</span><span class="punctuation token">(</span><span class="class-name token">Array</span><span class="punctuation token">.</span>prototype<span class="punctuation token">.</span><span class="function token">map</span><span class="punctuation token">.</span><span class="function token">call</span><span class="punctuation token">(</span>document<span class="punctuation token">.</span><span class="function token">querySelectorAll</span><span class="punctuation token">(</span><span class="string token">'script[type=\'text\/js-worker\']'</span><span class="punctuation token">)</span><span class="punctuation token">,</span> <span class="keyword token">function</span> <span class="punctuation token">(</span><span class="parameter token">oScript</span><span class="punctuation token">)</span> <span class="punctuation token">{</span> <span class="keyword token">return</span> oScript<span class="punctuation token">.</span>textContent<span class="punctuation token">;</span> <span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">,</span><span class="punctuation token">{</span>type<span class="punctuation token">:</span> <span class="string token">'text/javascript'</span><span class="punctuation token">}</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
<span class="comment token">// Создание нового свойства document.worker, содержащего все наши "text/js-worker" скрипты.</span>
document<span class="punctuation token">.</span>worker <span class="operator token">=</span> <span class="keyword token">new</span> <span class="class-name token">Worker</span><span class="punctuation token">(</span>window<span class="punctuation token">.</span><span class="constant token">URL</span><span class="punctuation token">.</span><span class="function token">createObjectURL</span><span class="punctuation token">(</span>blob<span class="punctuation token">)</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
document<span class="punctuation token">.</span>worker<span class="punctuation token">.</span><span class="function function-variable token">onmessage</span> <span class="operator token">=</span> <span class="keyword token">function</span><span class="punctuation token">(</span><span class="parameter token">oEvent</span><span class="punctuation token">)</span> <span class="punctuation token">{</span>
<span class="function token">pageLog</span><span class="punctuation token">(</span><span class="string token">'Received: '</span> <span class="operator token">+</span> oEvent<span class="punctuation token">.</span>data<span class="punctuation token">)</span><span class="punctuation token">;</span>
<span class="punctuation token">}</span><span class="punctuation token">;</span>
<span class="comment token">// Запуск воркера.</span>
window<span class="punctuation token">.</span><span class="function function-variable token">onload</span> <span class="operator token">=</span> <span class="keyword token">function</span><span class="punctuation token">(</span><span class="punctuation token">)</span> <span class="punctuation token">{</span> document<span class="punctuation token">.</span>worker<span class="punctuation token">.</span><span class="function token">postMessage</span><span class="punctuation token">(</span><span class="string token">''</span><span class="punctuation token">)</span><span class="punctuation token">;</span> <span class="punctuation token">}</span><span class="punctuation token">;</span>
</span></span><span class="tag token"><span class="tag token"><span class="punctuation token"></</span>script</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>head</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>body</span><span class="punctuation token">></span></span><span class="tag token"><span class="tag token"><span class="punctuation token"><</span>div</span> <span class="attr-name token">id</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>logDisplay<span class="punctuation token">"</span></span><span class="punctuation token">></span></span><span class="tag token"><span class="tag token"><span class="punctuation token"></</span>div</span><span class="punctuation token">></span></span><span class="tag token"><span class="tag token"><span class="punctuation token"></</span>body</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>html</span><span class="punctuation token">></span></span></code>
</pre>
<div id="logDisplay">Встраиваемый worker теперь внесен в новое custom свойство <code>document.worker</code></div>
<div></div>
<div>Также стоит отметить, что вы также можете преобразовать функцию в BLOB-объект, а затем сгенерировать URL объекта из этого BLOB-объекта. Например:</div>
<pre class="notranslate">function fn2workerURL(fn) {
var blob = new Blob(['('+fn.toString()+')()'], {type: 'application/javascript'})
return URL.createObjectURL(blob)
}
</pre>
<h2 id="Другие_примеры">Другие примеры</h2>
<p>В этой секции представлено еще несколько примеров как использовать worker-ы.</p>
<h3 id="Выполнение_вычислений_в_фоне">Выполнение вычислений в фоне</h3>
<p>Worker-ы в основном полезны для того, чтобы позволить вашему коду выполнять ресурсоемкие вычисления, не блокируя поток пользовательского интерфейса. В этом примере, worker используется для вычисления числа Фибоначчи.</p>
<h4 id="Код_JavaScript">Код JavaScript</h4>
<p>Следующий код JavaScript хранится в файле "fibonacci.js", на который ссылается HTML в следующем разделе.</p>
<pre class="brush: js notranslate">var results = [];
function resultReceiver(event) {
results.push(parseInt(event.data));
if (results.length == 2) {
postMessage(results[0] + results[1]);
}
}
function errorReceiver(event) {
throw event.data;
}
onmessage = function(event) {
var n = parseInt(event.data);
if (n == 0 || n == 1) {
postMessage(n);
return;
}
for (var i = 1; i <= 2; i++) {
var worker = new Worker("fibonacci.js");
worker.onmessage = resultReceiver;
worker.onerror = errorReceiver;
worker.postMessage(n - i);
}
};</pre>
<p>Worker устанавливает свойство <code>onmessage</code> для функции, которая будет получать сообщения, отправленные при вызове <code>postMessage()</code> рабочего объекта (обратите внимание, что это отличается от определения глобальной <em>переменной</em> с таким именем или определения <em>функции</em> с таким именем. <code>var onmessage</code> и <code>function onmessage</code> будет определять глобальные свойства с этими именами , но они не будут регистрировать функцию для получения сообщений, отправленных веб-страницей, которая создала worker). Это запускает рекурсию, порождая новые копии для обработки каждой итерации вычисления.</p>
<h4 id="HTML_код">HTML код</h4>
<pre class="brush: html line-numbers language-html notranslate"><code class="language-html"><span class="doctype token"><!DOCTYPE html></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>html</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>head</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>meta</span> <span class="attr-name token">charset</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>UTF-8<span class="punctuation token">"</span></span> <span class="punctuation token">/></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>title</span><span class="punctuation token">></span></span>Test threads fibonacci<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>title</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>head</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>body</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>div</span> <span class="attr-name token">id</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>result<span class="punctuation token">"</span></span><span class="punctuation token">></span></span><span class="tag token"><span class="tag token"><span class="punctuation token"></</span>div</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>script</span> <span class="attr-name token">language</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>javascript<span class="punctuation token">"</span></span><span class="punctuation token">></span></span><span class="script token"><span class="language-javascript token">
<span class="keyword token">var</span> worker <span class="operator token">=</span> <span class="keyword token">new</span> <span class="class-name token">Worker</span><span class="punctuation token">(</span><span class="string token">'fibonacci.js'</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
worker<span class="punctuation token">.</span><span class="function function-variable token">onmessage</span> <span class="operator token">=</span> <span class="keyword token">function</span><span class="punctuation token">(</span><span class="parameter token">event</span><span class="punctuation token">)</span> <span class="punctuation token">{</span>
document<span class="punctuation token">.</span><span class="function token">getElementById</span><span class="punctuation token">(</span><span class="string token">'result'</span><span class="punctuation token">)</span><span class="punctuation token">.</span>textContent <span class="operator token">=</span> event<span class="punctuation token">.</span>data<span class="punctuation token">;</span>
<span class="function token">dump</span><span class="punctuation token">(</span><span class="string token">'Got: '</span> <span class="operator token">+</span> event<span class="punctuation token">.</span>data <span class="operator token">+</span> <span class="string token">'\n'</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
<span class="punctuation token">}</span><span class="punctuation token">;</span>
worker<span class="punctuation token">.</span><span class="function function-variable token">onerror</span> <span class="operator token">=</span> <span class="keyword token">function</span><span class="punctuation token">(</span><span class="parameter token">error</span><span class="punctuation token">)</span> <span class="punctuation token">{</span>
<span class="function token">dump</span><span class="punctuation token">(</span><span class="string token">'Worker error: '</span> <span class="operator token">+</span> error<span class="punctuation token">.</span>message <span class="operator token">+</span> <span class="string token">'\n'</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
<span class="keyword token">throw</span> error<span class="punctuation token">;</span>
<span class="punctuation token">}</span><span class="punctuation token">;</span>
worker<span class="punctuation token">.</span><span class="function token">postMessage</span><span class="punctuation token">(</span><span class="string token">'5'</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
</span></span><span class="tag token"><span class="tag token"><span class="punctuation token"></</span>script</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>body</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>html</span><span class="punctuation token">></span></span></code></pre>
<p>Веб-страница создает элемент <code>div</code> с ID <code>result</code> , который используется для отображения результата, а затем порождает worker. После порождения worker-а, обработчик <code>onmessage</code> настроен для отображения результатов путем установки содержимого элемента <code>div</code>, и обработчик <code>onerror</code> настроен на <a href="/en-US/docs/Debugging_JavaScript#dump.28.29">выброс</a> сообщения об ошибке.</p>
<p>Наконец, сообщение отправляется worker-у, чтобы запустить его.</p>
<p><a class="external" href="/samples/workers/fibonacci">Попробуйте этот пример</a>.</p>
<h3 id="Выполнение_веб_IO_в_фоне">Выполнение веб I/O в фоне</h3>
<p>Вы можете найти пример этого в статье <a class="internal" href="/en-US/docs/Using_workers_in_extensions">Использование worker-ов в расширениях</a>.</p>
<h3 id="Разделение_задач_между_множественными_worker-ами">Разделение задач между множественными worker-ами</h3>
<p>Поскольку многоядерные компьютеры становятся все более распространенными, часто бывает полезно разделить вычислительно сложные задачи между несколькими worker-ами, которые затем могут выполнить эти задачи на многопроцессорных ядрах.</p>
<h2 id="Другие_типы_worker-ов">Другие типы worker-ов</h2>
<p>В дополнение к выделенным и совместно используемым web worker-ам доступны другие типы worker-ов:</p>
<ul>
<li><a href="/en-US/docs/Web/API/ServiceWorker_API">ServiceWorkers</a>, по сути, действуют как прокси-серверы, которые размещаются между веб-приложениями, браузером и сетью (при наличии). Они предназначены (помимо прочего) для создания эффективного автономного взаимодействия, перехвата сетевых запросов и принятия соответствующих действий в зависимости от того, доступна ли сеть, и обновлены ли ресурсы на сервере. Они также разрешают доступ push-уведомлениям и API фоновой синхронизации.</li>
<li>Chrome Workers это worker типа Firefox-only, который вы можете использовать, если вы разрабатываете дополнения и хотите использовать worker-ы в расширениях и иметь доступ к <a href="https://developer.mozilla.org/en/js-ctypes">js-ctypes</a> в вашем worker-е. Смотрите {{domxref("ChromeWorker")}} для более подробной информации.</li>
<li><a href="/en-US/docs/Web/API/Web_Audio_API#Audio_Workers">Audio Workers</a> предоставляют возможность прямой обработки звука по сценарию в контексте web worker-а.</li>
</ul>
<h2 id="Функции_и_интерфейсы_доступные_в_worker-ах">Функции и интерфейсы доступные в worker-ах</h2>
<p>Внутри web worker-а вы можете использовать большинство стандартных функций JavaScript, включая:</p>
<ul>
<li>{{domxref("Navigator")}}</li>
<li>{{domxref("XMLHttpRequest")}}</li>
<li>{{jsxref("Global_Objects/Array", "Array")}}, {{jsxref("Global_Objects/Date", "Date")}}, {{jsxref("Global_Objects/Math", "Math")}}, и {{jsxref("Global_Objects/String", "String")}}</li>
<li>{{domxref("Window.requestAnimationFrame")}}, {{domxref("WindowTimers.setTimeout")}}, и {{domxref("WindowTimers.setInterval")}}</li>
</ul>
<p>Главное, что вы не можете сделать в Worker это напрямую повлиять на родительскую страницу. Это включает в себя манипулирование DOM и использование объектов этой страницы. Вы должны сделать это косвенно, отправив сообщение обратно основному сценарию через {{domxref("DedicatedWorkerGlobalScope.postMessage")}}, а затем выполнив изменения оттуда.</p>
<div class="note">
<p><strong>Заметка</strong>: Для знакомства с полным списком функций, доступных для worker-ов, смотрите статью <a href="/en-US/docs/Web/Reference/Functions_and_classes_available_to_workers">Функции и интерфейсы доступные worker-ам</a>.</p>
</div>
<h2 id="Спецификации">Спецификации</h2>
<table class="standard-table">
<tbody>
<tr>
<th scope="col">Спецификация</th>
<th scope="col">Статус</th>
<th scope="col">Комментарий</th>
</tr>
<tr>
<td>{{SpecName('HTML WHATWG', '#toc-workers')}}</td>
<td>{{Spec2('HTML WHATWG')}}</td>
<td>Без изменений {{SpecName("Web Workers")}}.</td>
</tr>
<tr>
<td>{{SpecName('Web Workers')}}</td>
<td>{{Spec2('Web Workers')}}</td>
<td>Начальное определение.</td>
</tr>
</tbody>
</table>
<h2 id="Браузерная_совместимость">Браузерная совместимость</h2>
<div>{{CompatibilityTable}}</div>
<div id="compat-desktop">
<table class="compat-table">
<tbody>
<tr>
<th>Feature</th>
<th>Chrome</th>
<th>Firefox (Gecko)</th>
<th>Internet Explorer</th>
<th>Opera</th>
<th>Safari (WebKit)</th>
</tr>
<tr>
<td>Basic support</td>
<td>4<sup>[1]</sup></td>
<td>{{CompatGeckoDesktop("1.9.1")}}</td>
<td>10.0</td>
<td>10.6<sup>[1]</sup></td>
<td>4<sup>[2]</sup></td>
</tr>
<tr>
<td>Shared workers</td>
<td>4<sup>[1]</sup></td>
<td>{{CompatGeckoDesktop(29)}}</td>
<td>{{CompatNo}}</td>
<td>10.6</td>
<td>5<br>
{{CompatNo}} 6.1<sup>[4]</sup></td>
</tr>
<tr>
<td>Passing data using <a href="/en-US/docs/Web/Guide/API/DOM/The_structured_clone_algorithm">structured cloning</a></td>
<td>13</td>
<td>{{CompatGeckoDesktop(8)}}</td>
<td>10.0</td>
<td>11.5</td>
<td>6</td>
</tr>
<tr>
<td>Passing data using <a class="external" href="http://www.w3.org/html/wg/drafts/html/master/infrastructure.html#transferable-objects">transferable objects</a></td>
<td>17 {{property_prefix("webkit")}}<br>
21</td>
<td>{{CompatGeckoDesktop(18)}}</td>
<td>{{CompatNo}}</td>
<td>15</td>
<td>6</td>
</tr>
<tr>
<td>Global {{domxref("window.URL", "URL")}}</td>
<td>10<sup>[3]</sup><br>
23</td>
<td>{{CompatGeckoDesktop(21)}}</td>
<td>11</td>
<td>15</td>
<td>6<sup>[3]</sup></td>
</tr>
</tbody>
</table>
</div>
<div id="compat-mobile">
<table class="compat-table">
<tbody>
<tr>
<th>Feature</th>
<th>Android</th>
<th>Chrome for Android</th>
<th>Firefox Mobile (Gecko)</th>
<th>Firefox OS (Gecko)</th>
<th>IE Phone</th>
<th>Opera Mobile</th>
<th>Safari Mobile</th>
</tr>
<tr>
<td>Basic support</td>
<td>4.4</td>
<td>4<sup>[1]</sup></td>
<td>3.5</td>
<td>1.0.1</td>
<td>10.0</td>
<td>11.5<sup>[1]</sup></td>
<td>5.1<sup>[2]</sup></td>
</tr>
<tr>
<td>Shared workers</td>
<td>{{CompatNo}}</td>
<td>4<sup>[1]</sup></td>
<td>8</td>
<td>1.0.1</td>
<td>{{CompatNo}}</td>
<td>{{CompatNo}}</td>
<td>{{CompatNo}}</td>
</tr>
<tr>
<td>Passing data using <a href="/en-US/docs/Web/Guide/API/DOM/The_structured_clone_algorithm">structured cloning</a></td>
<td>{{CompatNo}}</td>
<td>4</td>
<td>8</td>
<td>1.0.1</td>
<td>{{CompatNo}}</td>
<td>{{CompatNo}}</td>
<td>{{CompatNo}}</td>
</tr>
<tr>
<td>Passing data using <a class="external" href="http://www.w3.org/html/wg/drafts/html/master/infrastructure.html#transferable-objects">transferable objects</a></td>
<td>{{CompatNo}}</td>
<td>{{CompatNo}}</td>
<td>18</td>
<td>1.0.1</td>
<td>{{CompatNo}}</td>
<td>{{CompatNo}}</td>
<td>{{CompatNo}}</td>
</tr>
</tbody>
</table>
</div>
<p>[1] Chrome и Opera выдают ошибку "<code>Uncaught SecurityError: Failed to construct 'Worker': Script at 'file:///Path/to/worker.js' cannot be accessed from origin 'null'.</code>" когда вы пытаетесь запустить worker локально. Нужно быть на надлежащем домене.</p>
<p>[2] Начиная с Safari 7.1.2, вы можете вызывать <code>console.log</code> изнутри worker-а, но он ничего не выведет в консоль. Более старые версии Safari не ползволяют вызывать <code>console.log</code> изнутри worker-а</p>
<p>[3] Эта функция реализована с префиксом как <code>webkitURL</code>.</p>
<p>[4] Safari <a href="https://bugs.webkit.org/show_bug.cgi?id=116359">удалил поддержку SharedWorker</a>.</p>
<h2 id="Смотрите_также">Смотрите также</h2>
<ul>
<li><code><a class="internal" href="/en-US/docs/Web/API/Worker">Worker</a></code> интерфейс</li>
<li><code><a class="internal" href="/en-US/docs/Web/API/SharedWorker">SharedWorker</a></code> интерфейс</li>
<li><a href="/en-US/docs/Web/API/Worker/Functions_and_classes_available_to_workers">Функции доступные для worker-ов</a></li>
<li><a href="/en-US/docs/Web/API/Web_Workers_API/Using_web_workers">Продвинутые концепции и примеры</a></li>
</ul>
|