Web Workers

Добавьте производительности своим Web приложениям

Сергей Мелашич
Agilie

Сергей

Мелашич

web разработчик компании Agilie

SergeyMell

Seroga.Mell

Sergey Melashych

sergey.mell@agilie.com

преподаватель school.agilie.com

Мы живем во многопоточном мире

World

Software

JavaScript

Мир JavaScript

Мир JavaScript

CORE

CORE

CORE

CORE

Мир JavaScript


 api.post('/login', userData)

   .then(response => {
     // Success stuff
   }, error => {
     // Error stuff
   });

 // Other stuff

APP THREAD

Action 1

Action 2

Action 3

Waiting for the response

Проблема однопоточности

CORE

CORE

CORE

CORE

Рендеринг чуть подробнее

Сколько времени у нас есть?

60 fps

16 ms

8 - 10 ms

"Тяжелые" операции

Обработка больших структур данных

Обработка изображений / звука

Генерация больших таблиц

Визуализация данных

...

Пример "тяжелой" операции

Решение?

1. setTimeout

2. iframe

3. Web Worker

Поддержка браузерами

Особенности Web Workers

1. Хранится в отдельном файле и запускается

как отдельный процесс

if (window.Worker) {
  const myWorker = new Worker("hard_worker.js");
}

2. Взаимодействие осуществляется посредством сообщений

myWorker.postMessage(data);

myWorker.onmessage = (event) => {
  console.log(event.data);
};

Особенности Web Workers

3. Нет доступа к DOM

4. Нет доступа к document, window, parent

5. Глобальный контекст доступен посредством self

Многопоточное исполнение

APP THREAD

WORKER THREAD

const myWorker = 
  new Worker("hard_worker.js");
myWorker.onmessage = ...
myWorker.postMessage(...);
renderResults(event.data);
self.onmessage = ...;
const result = 
  hardWork(event.data);
self.postMessage(result);

Блокировка рендеринга с решением

Shared Worker

const sharedWorker = new SharedWorker("shared.js");

sharedWorker.port.addEventListener("message", event => {
  // Subscribing Event
}, false);

sharedWorker.port.start();

sharedWorker.port.postMessage(data);

Передача данных в Web Worker

1. Структурное клонирование (structured cloning)

myWorker.postMessage(arrayOfData);

2. Передаваемые объекты (transferable objects)

myWorker.postMessage(arrayOfData, [arrayOfData]);

3. Широковещательный канал (broadcast channel)

let channel = new BroadcastChannel('channel-name');
channel.postMessage(data);

4. Общая память (shared memory)

const sharedBuffer = new SharedArrayBuffer(40);
myWorker.postMessage(sharedBuffer);

Библиотеки для работы
с Web Workers

Parallel.js

Hamsters.js

Web Workers во фреймворках

Web Workers во Vue.js

this.$worker.run((arg) => {
  return `Hello, ${arg}!`;
}, ['World'])

  .then(result => {
    console.log(result);
  })

  .catch(e => {
    console.error(e);
  });

https://github.com/israelss/vue-worker

Web Workers в React.js

https://github.com/web-perf/react-worker-dom

number of nodes

fps

react-renderer

react-worker-dom

Web Workers в Angular

UI THREAD

WORKER THREAD

Бизнес
логика

Пользовательское событие

postMessage('call');

Связанные данные

postMessage(data);

Как это сделать?

import '../polyfills.ts';
import '@angular/core';
import '@angular/common';
import {platformWorkerAppDynamic} from '@angular/platform-webworker-dynamic';

import { AppModule } from '../app/app.module';

platformWorkerAppDynamic().bootstrapModule(AppModule);
bootstrapWorkerUi('../webworker.bundle.js');
import { WorkerAppModule } from '@angular/platform-webworker';

webworker.ts

main.ts

app.module.ts

Angular на  стероидах  WebWorker-ах

А как же роутинг?

@NgModule({
    ...,
    providers: [
        ...,
        {provide: APP_BASE_HREF, useValue: '/'},
        WORKER_APP_LOCATION_PROVIDERS,
    ]
});

app.module.ts

bootstrapWorkerUi(
    '../webworker.bundle.js',
    WORKER_UI_LOCATION_PROVIDERS
);

main.ts

Тестирование производительности

fps

интенсивность мутаций

 Angular clean

 Angular worker

Полезные ссылки

Благодарю за внимание

Пожалуйста, разбудите спящих соседей

SergeyMell

Seroga.Mell

Sergey Melashych

sergey.mell@agilie.com

fwdays 2018

By Sergey Mell

fwdays 2018

  • 1,915