Favicon
на стероидах
Амосов Александр, AVITO
email: s9k0@ya.ru
twitter: @gc_s9k
Задача
2
• Messenger для обмена сообщениями между продавцом и покупателем
• Привлечь внимание пользователя, когда приходит новое сообщение
Задача
1. Отображать favicon с количеством
непрочитанных сообщений
3
Задача
1. Отображать favicon с количеством
непрочитанных сообщений
2. Не отображать favicon на активной вкладке
4
Задача
1. Отображать favicon с количеством
непрочитанных сообщений
2. Не отображать favicon на активной вкладке
3. Favicon должен мигать
5
• Создать заранее все картинки
• Создавать динамически с помощью canvas
Отрисовка favicon
6
1 2 3 …
Отрисовка favicon
const canvas = document.createElement('canvas');
canvas.width = SIZE;
canvas.height = SIZE;
const context = canvas.getContext('2d');
Создаем canvas и
получаем 2d контекст
7
Отрисовка favicon
const canvas = document.createElement('canvas');
canvas.width = SIZE;
canvas.height = SIZE;
const context = canvas.getContext('2d');
context.fillStyle = '#ff6163';
context.beginPath();
context.arc(SIZE / 2, SIZE / 2, SIZE / 2, 0, 2 * Math.PI);
context.fill();
8
Отрисовка favicon
const canvas = document.createElement('canvas');
canvas.width = SIZE;
canvas.height = SIZE;
const context = canvas.getContext('2d');
context.fillStyle = '#ff6163';
context.beginPath();
context.arc(SIZE / 2, SIZE / 2, SIZE / 2, 0, 2 * Math.PI);
context.fill();
context.fillStyle = 'white';
context.font = `${fontSize}px Arial`;
context.textAlign = 'center';
context.textBaseline = 'middle';
context.fillText(number, SIZE / 2, SIZE / 2);
2
9
Отрисовка favicon
const iconNode = document.createElement('link');
iconNode.rel = 'icon';
iconNode.type = 'image/png';
iconNode.href = canvas.toDataURL('image/png');
document.head.appendChild(iconNode);
Создаем элемент иконки
и добавляем в head
10
Отрисовка favicon
11
IE и Edge
12
• Не работают base64 фавиконки
• Не работает смена фавиконок
Задача
1. Отображать favicon с количеством
непрочитанных сообщений
2. Не отображать favicon на активной вкладке
3. Favicon должен мигать
13
Visibility API
14
15
document.addEventListener('visibilitychange', () => {
const isVisible = !document.hidden;
// ...
});
Visibility API
16
Задача
1. Отображать favicon с количеством
непрочитанных сообщений
2. Не отображать favicon на активной вкладке
3. Favicon должен мигать
17
Мигание
• setInterval
18
Мигание
• setInterval
19
Мигание
• setInterval
• gif?
20
Мигание
• setInterval
• gif
• Web Worker
21
Web Worker
• Выполняются в отдельном потоке
• Код находится в отдельном файле
• Нельзя манипулировать DOM
• Нет requestAnimationFrame
• Общение через сообщения
• Имеют свой глобальный объект
22
Доступно
• Объект navigator, location
• Fetch / XMLHttpRequest / WebSocket
• setTimeout()/clearTimeout() и setInterval()/clearInterval()
• IndexedDB
• Создание других Web Worker’ов
23
Обмен сообщениями
• Простые типы данных
24
Пример
const worker = new Worker('worker.js');
worker.postMessage('request');
worker.onmessage = ({ data }) => {
console.log(data);
};
onmessage = ({ data }) => {
console.log(data);
postMessage('answer');
};
worker.jsmain.js
25
Обмен сообщениями
• Простые типы данных
• Объекты
26
Пример
onmessage = ({ data }) => {
console.log(data);
postMessage('answer');
};
worker.jsmain.js
const worker = new Worker('worker.js');
worker.postMessage({ arr: [2, 3] });
worker.onmessage = ({ data }) => {
console.log(data);
};
27
Обмен сообщениями
• Простые типы данных
• Объекты
• Transferrable objects
28
worker.jsmain.js
const typedArray = new Uint8Array([0, 1, 2]);
const worker = new Worker('worker.js');
worker.postMessage(typedArray, [typedArray.buffer]);
worker.onmessage = ({ data }) => {
console.log(data);
};
onmessage = ({ data: typedArray }) => {
postMessage(typedArray, [typedArray.buffer]);
};
29
Применение
• Для обработки больших объемов данных в отдельном потоке
• обработка текста
• обработка изображений, видео, аудио
• обработка данных после получения через ajax
• расчет физики в играх
30
Применение
• Для обработки больших объемов данных в отдельном потоке
• обработка текста
• обработка изображений, видео, аудио
• обработка данных после получения через ajax
• расчет физики в играх
• Для использования intervals/timeouts без ограничений
31
let intervalId;
const INTERVAL_TIME = 2000;
onmessage = function({ data }) {
switch (data) {
case 'start':
clearInterval(intervalId);
intervalId = setInterval(() => {
postMessage('tick');
}, INTERVAL_TIME);
break;
case 'stop':
clearInterval(intervalId);
break;
}
};
32
Web Worker
33
Задача
1. Отображать favicon с количеством непрочитанных
сообщений
2. Не отображать favicon на активной вкладке
3. Favicon должен мигать
4. Несколько вкладок должны мигать синхронно O_o
34
Синхронизация
• SharedWorker
35
SharedWorker
• Может связываться сразу с несколькими контекстами
• Работает пока не закроются все страницы, его использующие
36
worker.js
main.js
const worker = new SharedWorker('worker.js');
worker.port.postMessage('start');
worker.port.onmessage = ({ data }) => {
console.log(data);
};
const ports = [];
onconnect = ({ ports: [port] }) => {
ports.push(port);
port.onmessage = ({ data }) => {
if (data === 'start') {
port.postMessage(`connection: ${ports.length}`);
}
};
};
37
Применение
• Расшаренный между вкладками WebSocket
38
39
const ports = [];
const INTERVAL_TIME = 2000;
setInterval(() => {
ports.forEach(port => {
port.postMessage('tick');
});
}, INTERVAL_TIME);
onconnect = (event) => {
const port = event.ports[0];
ports.push(port);
};
40
Синхронизация
• SharedWorker
• Нить времени
41
10:00 10:02 10:04 10:06 10:08 10:10
42
10:00 10:02 10:04 10:06 10:08 10:10
43
10:00 10:02 10:04 10:06 10:08 10:10
44
let timeoutId;
const INTERVAL_TIME = 2000;
function tick() {
const timeToStart = INTERVAL_TIME - Date.now() % INTERVAL_TIME;
timeoutId = setTimeout(tick, timeToStart);
postMessage('tick');
}
onmessage = function({ data }) {
switch (data) {
case 'start':
clearTimeout(timeoutId);
tick();
break;
case 'stop':
clearTimeout(timeoutId);
break;
}
};
45
10:00 10:02 10:04 10:06 10:08 10:10
2 2
46
Проблемы
• В Chrome 54 ограничение на веб воркер в неактивной вкладке
• На каждую вкладку создается свой веб воркер
47
48
49
Shared Worker
Dedicated Worker
setInterval
Задача
1. Отображать favicon с количеством непрочитанных
сообщений
2. Не отображать favicon на активной вкладке
3. Favicon должен мигать
4. Несколько вкладок должны мигать синхронно
50
51
setInterval, setTimeout на Воркерах
http://bit.ly/timersjs
Спасибо! Вопросы?
52
Амосов Александр
email: s9k0@ya.ru
twitter: @gc_s9k
http://bit.ly/timersjs

"Favicon на стероидах" Александр Амосов (Avito)