MediaDevices.getUserMedia() - Интерфейсы веб API

MediaDevices.getUserMedia()
===========================

Метод `MediaDevices`**`.getUserMedia()`**, при выполнении, вызывает всплывающий диалог, запрашивающий разрешение пользователя на использование медиа устройства (камера, микрофон). Результат возвращает промис, содержащий поток, который состоит из треков (дорожек), содержащих требуемые медиа типы. Этот поток может включать, к примеру, видеотрек, созданный либо аппаратным средством, либо виртуальным видеоисточником, такими как камера, устройство видеозаписи, сервис обмена изображениями и т.д); аудиотрек, созданный физическим или виртуальным аудиоисточником, к примеру, микрофоном, аналого-цифровым преобразователем звуков и возможно иные типы треков.

Он возвращает `Promise` , который, в случае согласия пользователя, разрешается `MediaStream` объектом. Если пользователь отказывает в разрешении, или медиа устройство не доступно, тогда промис отменяется с объектами типа `NotAllowedError` или `NotFoundError` соответственно.

**Примечание:** Возможно, что промис ни разрешиться, ни отмениться, в случае, когда пользователь не сделает выбор и запрос проигнорирует.

Обычно, разработчик получает доступ к единственному экземпляру объекта `MediaDevices` , используя `navigator.mediaDevices.getUserMedia()` (en-US) метод, возвращающий поток:

```js
async function getMedia(constraints) {
  let stream = null;

  try {
    stream = await navigator.mediaDevices.getUserMedia(constraints);
    /\* используем поток \*/
  } catch (err) {
    /\* обработка ошибки \*/
  }
}
```

Тот же результат, но используя тип промиса :

```js
navigator.mediaDevices
  .getUserMedia(constraints)
  .then(function (stream) {
    /\* используем поток \*/
  })
  .catch(function (err) {
    /\* обработка ошибки \*/
  });
```

**Примечание:** Если документ загружен не безопасно, значение `navigator.mediaDevices` будет `undefined`, и нельзя будет использовать метод `getUserMedia()`. Смотри Security для дополнительной информации о дальнейших вопросах безопасности, связанной с использованием метода `getUserMedia()`.

Синтаксис
---------
```

var promise = navigator.mediaDevices.getUserMedia(constraints);
```

### Параметры

`constraints (ограничения)`

Объект `MediaStreamConstraints` (en-US), определяющий запрашиваемые медиатипы, вместе с требованиями для каждого типа.

Тип параметра `constraints` (ограничения) - это объект типа `MediaStreamConstraints` с двумя членами: `video` и `audio`, описывающие запрашиваемые медиатипы. Один или оба должны определяться разработчиком. Если браузер не сможет обнаружить медиатреки определяемого типа, которые соответствуют переданным ограничениям, возвращаемый методом промис отменяется с объектом `NotFoundError`.

Следующий отрывок кода запрашивает и `audio` и `video` типы без дополнительных условий:

```js
{ audio: true, video: true }
```

Если определяется значение `true` для медиатипа, результирующий поток обязательно будет иметь в себе запрошенный медиатип. Если ни один из типов не включается в запрос, вызов метода `getUserMedia()` приведёт к ошибке.

Если полная информация о камерах и микрофонах пользователя недоступна по причинам конфиденциальности, приложение может запросить доступ только к необходимым ему функциям, используя дополнительные условия. Следующий пример запрашивает видеотрек с разрешением камеры 1280x720 пикселей:

```js
{
  audio: true,
  video: { width: 1280, height: 720 }
}
```

Браузер попытается выполнить условие, но может вернуть видеотрек другого разрешения, если установленные требования невозможно удовлетворить (камера не обладает возможностью такого разрешения), или пользователь переопределяет условие.

Для минимального, максимального и точного определения значения можно использовать ключевые слова `min`, `max`, или `exact`. Следующий пример запрашивает минимальное разрешение камеры 1280x720:

```js
{
  audio: true,
  video: {
    width: { min: 1280 },
    height: { min: 720 }
  }
}
```

Если камера не в состоянии обеспечить указанное минимальное разрешение или более высокое, возвращаемый промис будет отменён с объектом `OverconstrainedError`, и пользователь не увидит диалога запроса разрешения.

Различие поведения происходит по причине того, что ключевые слова `min`, `max`, и `exact` являются обязательными к выполнению. В то время как простые значения и ключевое слово `ideal` - не обязательные к выполнению. Ниже, полный пример:

```js
{
  audio: true,
  video: {
    width: { min: 1024, ideal: 1280, max: 1920 },
    height: { min: 776, ideal: 720, max: 1080 }
  }
}
```

Значение свойства `ideal` имеет приоритет. Это означает, что браузер будет пытаться обнаружить настройки с наименьшей fitness distance (удовлетворяющей разницей) от переданных идеальных значений. Т.е. пытается найти самое близкое к переданному значение.

Простые значения работают как идеальные, поэтому один из первых примеров выше можно переписать, используя свойство `ideal`:

```js
{
  audio: true,
  video: {
    width: { ideal: 1280 },
    height: { ideal: 720 }
  }
}
```

Не все значения ограничений являются числовыми. К примеру, на мобильных устройствах следующий отрывок будет запрашивать переднюю камеру (если присутствует) , поэтому в свойстве `facingMode` указано строковое значение `user`:

```js
{ audio: true, video: { facingMode: "user" } }
```

Запрос обратной (задней) камеры:

```js
{ audio: true, video: { facingMode: { exact: "environment" } } }
```

Следующее строковое свойство - `deviceId` (идентификатор устройства). Его значение может быть получено из метода `mediaDevices.enumerateDevices()`, возвращающего список, имеющихся на машине устройств, с их идентификаторами, и может быть использовано для запроса определённого устройства по идентификатору этого устройства:

```js
{
  video: {
    deviceId: идентификаторНужнойКамеры;
  }
}
```

Код выше вернёт запрашиваемую камеру или другую камеру, если требуемая камера недоступна. Для получения доступа к потоку только определённой камеры, без альтернативы, используется свойство `exact` (точно) :

```js
{
  video: {
    deviceId: {
      exact: идентификаторНужнойКамеры;
    }
  }
}
```

### Возвращаемое значение

Промис `Promise`, при удачном запросе требуемого медиа устройства разрешается объектом типа `MediaStream` .

### Исключения (Ошибки)

При неудачном запросе медиа устройства, возвращаемый промис `Promise` отменяется объектом типа ошибки `DOMException` (en-US). Возможными ошибками могут быть типы:

`AbortError (Прервано)`

Хотя пользователь и операционная система предоставили доступ к аппаратному устройству, и не возникло проблем с оборудованием, которые могли бы вызвать `NotReadableError`, возникла некоторая проблема, которая не позволила использовать устройство.

`NotAllowedError (Доступ не разрешён)`

Возникает если, одно или несколько запрашиваемых устройств не может быть использованы в настоящее время. Это происходит тогда, когда контекст браузера является не безопасным (страница была загружена используя протокол HTTP вместо HTTPS), а также, если пользователь не разрешил доступ текущему экземпляру браузера к устройству, пользователь отказал в доступе в текущей сессии, или пользователь отказал в доступе к медиаустройствам глобально. Для браузеров, которые поддерживают управление медиаразрешениями с помощью Feature Policy, такая ошибка возвращается если Feature Policy не сконфигурирована для разрешение доступа к медиаустройству или устройствам

**Примечание:** Более старые версии спецификации использовали вместо этого SecurityError. `SecurityError` имеет новое значение.

`NotFoundError (Не найдено)`

Возникает если, типы медиа треков, удовлетворяющие переданным значениям, не найдены.

`NotReadableError (Не читается)`

Хотя пользователь и предоставил разрешение на использование соответствующих устройств, произошла аппаратная ошибка на уровне операционной системы, браузера или веб-страницы, которая препятствовала доступу к устройству..

`OverconstrainedError (за границами ограничений)`

Возникает если, в результате указанных ограничений не было найдено устройств, отвечающих запрошенным критериям. Ошибка является объектом типа `OverconstrainedError` и имеет свойство `constraint`, строковое значение которого является именем ограничения, которое было невозможно встретить, и свойство `message`, содержащее читаемую человеком строку, объясняющую проблему.

**Примечание:** Ошибка может возникнуть даже, если пользователь ещё не выдал разрешение на использование устройства, использующиеся как поверхность для идентификации отпечатка пальца.

`SecurityError (ошибка безопасности)`

Возникает если, медиа поддержка отключена в `Document` на котором был вызван метод `getUserMedia()`. Механизм по которому медиа поддержка включается и отключается находиться в компетенции браузера пользователя.

`TypeError (ошибка типа)`

Возникает если, список ограничений пустой или все ограничения установлены в `false`. Так же это происходит, если пытаться вызвать метод `getUserMedia()` в небезопасном контексте, поскольку в нем `navigator.mediaDevices` равно `undefined`.

Конфиденциальность и безопасность
---------------------------------

Поскольку API могут существенно затрагивать вопросы конфиденциальности, спецификация `getUserMedia()` предъявляет широкий спектр требований защиты конфиденциальности и безопасности, которым современные браузеры обязаны следовать.

`getUserMedia()` - это мощная функция, которая может быть использована только в безопасном контексте (en-US) . В небезопасном контексте, `navigator.mediaDevices` равно `undefined`, предотвращая доступ к методу `getUserMedia()`. Безопасный контекст - это, если кратко, страница, загружаемая по протоколу HTTPS или `file:///` URL схеме, или страница, загружаемая из `localhost`.

В нем обязательно запрашивается пользовательское разрешение к доступу `audio` или `video` источникам. Только контекст документа верхнего уровня, проверенного источника может запросить доступ, используя метод `getUserMedia()`. Если контексту верхнего уровня явно не даётся разрешение для данного `<iframe>` (en-US) используя Feature Policy, пользователю никогда не будет предложено выдать разрешение на использование устройств, пока пользователь самостоятельно не отменит запрет в настройках браузера.

Дополнительные подробности на тему требований и правил, и как они отражены в контексте выполняемого кода, о том, как браузеры управляют вопросами конфиденциальности и безопасности читайте далее.

### Конфиденциальность пользователя

Поскольку, программный интерфейс затрагивает вопросы конфиденциальности и безопасности, в спецификации, для метода `getUserMedia()` содержатся особенные требования для управления уведомлениями и разрешениями пользователя. Сначала метод `getUserMedia()` должен всегда запрашивать пользовательское разрешение до начала сбора данных потоков камеры и микрофона. Браузер может использовать функциональность одного разрешения на домен, но в первый раз браузер обязательно должен получить разрешение пользователя.

Не менее важны правила уведомления. Браузеры обязательно отображают индикатор, который указывает на использование камеры или микрофона, выше или сверху любого, уже имеющегося индикатора аппаратного средства (если присутствует). Они также должны отображать индикатор того, что разрешение уже выдано для использования устройств, даже, если устройства не используются в настоящий момент.

К примеру, в Firefox, в панели адреса отображается красная пульсирующая иконка, указывающая на использование аппаратного средства. Серая иконка указывает на выданное разрешение, но не использование аппаратного средства в данный момент. Физический (явный) свет устройства указывает на текущее использование (активизацию) аппаратного средства. Если отключить камеру программно, свет активности камеры отключится, указывая на то, что она запись не производит, без отмены разрешение на использования, и включиться после запуска камеры в работу.

### Безопасность

Существуют несколько способов управлением безопасностью и контролем в user agent. Для этого можно использовать метод `getUserMedia()` , который возвращает объекты ошибок, относящиеся к безопасности.

**Примечание:** Модель безопасности для метода `getUserMedia()` находиться в процессе разработки. Первоначально спроектированный механизм безопасности находиться в процессе замещения Feature Policy, поэтому различные браузеры имеют разный уровень поддержки безопасности, используют различные механизмы. Вам необходимо осторожно тестировать свой код на различных устройствах и браузерах, чтобы удостовериться в его уверенной работоспособности.

#### Feature Policy (Функциональная политика)

Функция управление безопасностью (Feature Policy) протокола HTTP находиться в процессе введения в браузеры, с поддержкой, доступной в различной степени во многих браузерах (но не всегда включённой в настройках по умолчанию, как в Firefox). Метод `getUserMedia()` - один из методов, требующий использования функциональной политики и вашему коду нужно быть готовым к работе с ним. К примеру, чтобы метод был доступен в документах не высокого уровня, разработчику нужно использовать либо атрибут `allow` (en-US) на элементе `<iframe>` (en-US) , который использует `getUserMedia()`, либо `Feature-Policy` (en-US) заголовок для страниц , передающихся с сервера, которые используют `getUserMedia()`.

Два разрешения, которые обращаются к `getUserMedia()` - `camera` и `microphone`.

К примеру, строка HTTP заголовка позволит использовать камеру документу и любым встроенные `<iframe>` (en-US) элементам, которые загружаются из одного источника:
```

Feature-Policy: camera 'self'
```

Строка ниже, запрашивает доступ к микрофону для текущего источника и указанном в заголовке источнике `https://developer.mozilla.org`:
```

Feature-Policy: microphone 'self' https://developer.mozilla.org
```

Если используется `getUserMedia()` внутри элемента `<iframe>`, можно запросить разрешение только для этого фрейма, которое явно более безопаснее, чем запрашивать более общее разрешение. Здесь нам нужно использовать и камеру и микрофон:

```html
<iframe src="https://mycode.example.net/etc" allow="camera;microphone">
</iframe>
```

#### Безопасность на основе шифрования

Метод `getUserMedia()` доступен *только* для безопасных контекстов (en-US). Безопасный контекст - это уверенность браузера в том, что документ был загружен безопасно, используя HTTPS/TLS, и имеет ограниченную подверженность небезопасным контекстам. Если документ не загружен в безопасном контексте, свойство `navigator.mediaDevices` равно `undefined`, делая невозможным доступ к методу `getUserMedia()`. Попытка получить доступ в такой ситуации приведёт к ошибке `TypeError`.

#### Безопасность источника документа

Существуют несколько небезопасных способа загрузить документ, который может попытаться вызвать метод `getUserMedia()`. Ниже представлены примеры ситуаций, в которых `getUserMedia()` не разрешается вызывать:

* Документ, загруженный в песочницу `<iframe>` (en-US) элемента не может вызвать `getUserMedia()`, до тех пор пока, на элементе `<iframe>` находиться атрибут `sandbox` (en-US), установленный в значение `allow-same-origin`.
* Документ, загруженный по протоколам `data://` или `blob://` в URL-адресе, не имеющий источника (такими являются типы URL-ов, введённые пользователями в строке адреса браузера) не может вызвать `getUserMedia()`. Подобные типы URL-ов, загружаемые из JavaScript-кода, наследуют разрешения скрипта.
* Иные ситуации, документы которых не имеют источника, к примеру элемент, содержащий атрибут `srcdoc` (en-US), использующийся для указания содержимого фрейма.
Примеры
-------

### Ширина и высота

Этот пример выбирает указанное разрешение камеры и присваивает ссылку на объект `MediaStream` свойству `srcObject` элемента `video` .

```js
// Выбирает разрешение камеры близкое к 1280x720.
var constraints = { audio: true, video: { width: 1280, height: 720 } };

navigator.mediaDevices
  .getUserMedia(constraints)
  .then(function (mediaStream) {
    var video = document.querySelector("video");
    video.srcObject = mediaStream;
    video.onloadedmetadata = function (e) {
      video.play();
    };
  })
  .catch(function (err) {
    console.log(err.name + ": " + err.message);
  }); // always check for errors at the end.
```

### Использование новых API в старых браузерах

Ниже, находятся примеры, использующие `navigator.mediaDevices.getUserMedia()`, с полифилами для работы в старых браузерах. Обратите внимание, что эти полифилы не корректируют все различия в синтаксисе, и не работают во всех браузерах. Рекомендуется использовать библиотеку adapter.js , как производственный полифил.

```js
// Старые браузеры могут не реализовывать свойство mediaDevices,
// поэтому сначала присваиваем свойству ссылку на пустой объект

if (navigator.mediaDevices === undefined) {
  navigator.mediaDevices = {};
}

// Некоторые браузеры частично реализуют свойство mediaDevices, поэтому
//мы не можем присвоить ссылку на объект свойству getUserMedia, поскольку
//это переопределит существующие свойства. Здесь, просто добавим свойство
//getUserMedia , если оно отсутствует.

if (navigator.mediaDevices.getUserMedia === undefined) {
  navigator.mediaDevices.getUserMedia = function (constraints) {
    // Сначала, если доступно, получим устаревшее getUserMedia

    var getUserMedia =
      navigator.webkitGetUserMedia || navigator.mozGetUserMedia;

    //Некоторые браузеры не реализуют его, тогда вернём отменённый промис
    // с ошибкой для поддержания последовательности интерфейса

    if (!getUserMedia) {
      return Promise.reject(
        new Error("getUserMedia is not implemented in this browser"),
      );
    }

    // Иначе, обернём промисом устаревший navigator.getUserMedia

    return new Promise(function (resolve, reject) {
      getUserMedia.call(navigator, constraints, resolve, reject);
    });
  };
}

navigator.mediaDevices
  .getUserMedia({ audio: true, video: true })
  .then(function (stream) {
    var video = document.querySelector("video");
    // Устаревшие браузеры могут не иметь свойство srcObject
    if ("srcObject" in video) {
      video.srcObject = stream;
    } else {
      // Не используем в новых браузерах
      video.src = window.URL.createObjectURL(stream);
    }
    video.onloadedmetadata = function (e) {
      video.play();
    };
  })
  .catch(function (err) {
    console.log(err.name + ": " + err.message);
  });
```

### Частота кадров

В некоторых случаях может быть желательна более низкая частота кадров, например, при передаче WebRTC с ограничениями полосы пропускания

```js
var constraints = { video: { frameRate: { ideal: 10, max: 15 } } };
```

### Передняя и задняя камеры

На мобильных устройствах.

```js
var front = false;
document.getElementById("flip-button").onclick = function () {
  front = !front;
};

var constraints = { video: { facingMode: front ? "user" : "environment" } };
```

Спецификации
------------

| Specification |
| --- |
| Media Capture and Streams # dom-mediadevices-getusermedia |

Совместимость с браузерами
--------------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Смотрите также
--------------

* Предыдущее `navigator.getUserMedia()` API.
* `mediaDevices.enumerateDevices()`: Перечисление доступных медиа устройств
* WebRTC API
* Media Capture and Streams API (Media Streams) (en-US)
* Screen Capture API (en-US): Захват области экрана как `MediaStream`
* `mediaDevices.getDisplayMedia()` (en-US): Получение потока, содержащего экранную область
* Taking webcam photos: Руководство по использованию `getUserMedia()` для получения снимком вместо видео.


MediaDevices.enumerateDevices() - Интерфейсы веб API

MediaDevices.enumerateDevices()
===============================

**Экспериментальная возможность:** **Это экспериментальная технология**
Так как спецификация этой технологии ещё не стабилизировалась, смотрите таблицу совместимости по поводу использования в различных браузерах. Также заметьте, что синтаксис и поведение экспериментальной технологии может измениться в будущих версиях браузеров, вслед за изменениями спецификации.

Метод **`MediaDevices.enumerateDevices()`** собирает информацию о медиа-устройствах ввода и вывода, доступных в системе.

Синтаксис
---------
```

navigator.mediaDevices.enumerateDevices()
.then(function(MediaDeviceInfo) { ... })
```

### Возвращаемое значение

Возвращает `Promise` (en-US) который, если выполнится успешно, вернёт массив экземпляров `MediaDeviceInfo` (en-US) , которые содержат информацию о доступных медиа-устройствах ввода и вывода.

Пример
------

Ниже, пример, использующий метод `mediaDevices.enumerateDevices()`.

```js
if (!navigator.mediaDevices || !navigator.mediaDevices.enumerateDevices) {
  console.log("enumerateDevices() не поддерживается.");
  return;
}

// Перечисление в цикле камер и микрофонов

navigator.mediaDevices
  .enumerateDevices()
  .then(function (devices) {
    devices.forEach(function (device) {
      console.log(
        device.kind + ": " + device.label + " id = " + device.deviceId,
      );
    });
  })
  .catch(function (err) {
    console.log(err.name + ": " + err.message);
  });
```

результат перечисления в цикле:
```

videoinput: id = csO9c0YpAf274OuCPUA53CNE0YHlIr2yXCi+SqfBZZ8=
audioinput: id = RKxXByjnabbADGQNNZqLVLdmXlS0YkETYCIbg+XxnvM=
audioinput: id = r2/xw1xUPIyZunfV1lGrKOma5wTOvCkWfZ368XCndm0=
```

или, если один или более объектов `MediaStream` активны, или получены постоянные разрешения:
```

videoinput: FaceTime HD Camera (Built-in) id=csO9c0YpAf274OuCPUA53CNE0YHlIr2yXCi+SqfBZZ8=
audioinput: default (Built-in Microphone) id=RKxXByjnabbADGQNNZqLVLdmXlS0YkETYCIbg+XxnvM=
audioinput: Built-in Microphone id=r2/xw1xUPIyZunfV1lGrKOma5wTOvCkWfZ368XCndm0=
```

Разрешения
----------

Что бы использовать метод `enumerateDevices()` в устанавливаемом приложении (к примеру в Firefox OS приложение), необходимо указать оба поля внутри файла манифеста приложения:

```js
"permissions": {
  "audio-capture": {
    "description": "Required to capture audio using getUserMedia()"
  },
  "video-capture": {
    "description": "Required to capture video using getUserMedia()"
  }
}
```

Смотрите также : разрешение: аудио захват and разрешение : видео захват в продолжение темы.

Спецификации
------------

| Specification |
| --- |
| Media Capture and Streams # dom-mediadevices-enumeratedevices |

Совместимость с браузерами
--------------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Смотрите также
--------------

* navigator.mediaDevices.getUserMedia
* WebRTC (en-US) - the introductory page to the API
* MediaStream API (en-US) - the API for the media stream objects
* Taking webcam photos (en-US) - a tutorial on using `getUserMedia() for taking photos rather than video.`


DOMImplementation.createHTMLDocument() - Интерфейсы веб API

DOMImplementation.createHTMLDocument()
======================================

Метод **`DOMImplementation.createHTMLDocument()`** создаёт новый HTML `Document`.

Синтаксис
---------
```

const newDoc = document.implementation.createHTMLDocument(title)
```

### Параметры

`title` Необязательный (except in IE)

`DOMString`, содержащий заголовок для создания нового HTML-документа.

Пример
------

В этом примере создаётся новый HTML-документ и вставляется в `<iframe>` (en-US) текущего документа.

Вот HTML для этого примера:

```html
<body>
  <p>
    Click <a href="javascript:makeDocument()">here</a> to create a new document
    and insert it below.
  </p>
  <iframe id="theFrame" src="about:blank" />
</body>
```

Реализация JavaScript `makeDocument()` выглядит следующим образом:

```js
function makeDocument() {
  let frame = document.getElementById("theFrame");

  let doc = document.implementation.createHTMLDocument("New Document");
  let p = doc.createElement("p");
  p.innerHTML = "This is a new paragraph.";

  try {
    doc.body.appendChild(p);
  } catch (e) {
    console.log(e);
  }

  // Copy the new HTML document into the frame

  let destDocument = frame.contentDocument;
  let srcNode = doc.documentElement;
  let newNode = destDocument.importNode(srcNode, true);

  destDocument.replaceChild(newNode, destDocument.documentElement);
}
```

Код в строках 4-12 обрабатывает создание нового HTML-документа и вставку в него некоторого содержимого. Строка 4 использует `createHTMLDocument()` для создания нового HTML-документа, чей `<title>` это `"New Document"`. Строки 5 и 6 создают новый элемент абзаца с некоторым простым содержимым, а затем строки 8-12 обрабатывают вставку нового абзаца в новый документ.

Строка 16 вытягивает `contentDocument` фрейма; это документ, в который мы будем вводить новое содержимое. Следующие две строки обрабатывают импорт содержимого нашего нового документа в контекст нового документа. Наконец, строка 20 фактически заменяет содержимое фрейма содержимым нового документа.

Смотреть Видео Примеры

Возвращаемый документ предварительно сконструирован со следующим HTML-кодом:

```html
<!doctype html>
<html>
  <head>
    <title>title</title>
  </head>
  <body></body>
</html>
```

Спецификации
------------

| Specification |
| --- |
| DOM Standard # ref-for-dom-domimplementation-createhtmldocument① |

Совместимость с браузерами
--------------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Смотрите также
--------------

* Интерфейс `DOMImplementation`, к которому он принадлежит.


Запись медиа элемента - Интерфейсы веб API

Запись медиа элемента
=====================

В статье Использование интерфейса MediaStream Recording API демонстрируется использование объекта типа `MediaRecorder` для захвата потока, представляющего объект типа `MediaStream` , сгенерированного аппаратными средствами устройства и возвращаемого методом `navigator.mediaDevices.getUserMedia()`, но можно также использовать HTML медиа элемент (а именно `<audio>` или `<video>`) в качестве источника потока `MediaStream` для его записи. В этой статье рассматривается пример выполняющий это.

Пример записи с помощью медиа элемента
--------------------------------------

### HTML
```

<p>
  Click the "Start" button to begin video recording for a few seconds. You can
  stop the video by clicking the creatively-named "Stop" button. The "Download"
  button will download the received data (although it's in a raw, unwrapped form
  that isn't very useful).
</p>
<br />
```

Рассмотрим ключевые моменты кода HTML. Это только небольшой отрывок, относящийся к информационной части приложения.

```html
<div class="left">
  <div id="startButton" class="button">Start</div>
  <h2>Preview</h2>
  <video id="preview" width="160" height="120" autoplay muted></video>
</div>
```

Основной интерфейс представляется в двух колонках. В левой находиться кнопка старта и элемент `<video>` , который отображает предварительный просмотр видео. Это видео, воспроизводится камерой устройства. Заметьте, что используется атрибут `autoplay`, что бы поток начал воспроизводиться немедленно, снимаясь прямо с камеры. Атрибут `muted` гарантирует отключение звука с микрофона, для предотвращения цикличного эхо эффекта.

```html
<div class="right">
  <div id="stopButton" class="button">Stop</div>
  <h2>Recording</h2>
  <video id="recording" width="160" height="120" controls></video>
  <a id="downloadButton" class="button"> Download </a>
</div>
```

Справа мы видим кнопку остановки и элемент `<video>,` который будет использоваться для воспроизведения записанного видео. Обратите внимание, что на панели воспроизведения не установлен режим автозапуска (поэтому воспроизведение не начинается сразу после поступления мультимедиа), а также установлен атрибут `controls`, что говорит о необходимости показывать пользовательские элементы управления для воспроизведения, паузы и т. д.

Под элементом воспроизведения находится кнопка для загрузки записанного видео.
```

<div class="bottom">
  <pre id="log"></pre>
</div>
```

```
body {
  font:
    14px "Open Sans",
    "Arial",
    sans-serif;
}

video {
  margin-top: 2px;
  border: 1px solid black;
}

.button {
  cursor: pointer;
  display: block;
  width: 160px;
  border: 1px solid black;
  font-size: 16px;
  text-align: center;
  padding-top: 2px;
  padding-bottom: 4px;
  color: white;
  background-color: darkgreen;
  text-decoration: none;
}

h2 {
  margin-bottom: 4px;
}

.left {
  margin-right: 10px;
  float: left;
  width: 160px;
  padding: 0px;
}

.right {
  margin-left: 10px;
  float: left;
  width: 160px;
  padding: 0px;
}

.bottom {
  clear: both;
  padding-top: 10px;
}
```

### JavaScript

Теперь давайте посмотрим на код JavaScript

#### Установка глобальных переменных

Мы начнём с установления некоторых глобальных переменных, которые нам понадобятся.

```js
let preview = document.getElementById("preview");
let recording = document.getElementById("recording");
let startButton = document.getElementById("startButton");
let stopButton = document.getElementById("stopButton");
let downloadButton = document.getElementById("downloadButton");
let logElement = document.getElementById("log");

let recordingTimeMS = 5000;
```

Большинство из них являются ссылками на элементы, с которыми нам нужно работать. Последняя, `recordingTimeMS`, установлена на 5000 миллисекунд (5 секунд);.

#### Используемые функции

Далее мы создадим несколько служебных функций, которые будут использованы позже.

```js
function log(msg) {
  logElement.innerHTML += msg + "\n";
}
```

Функция `log ()` используется для вывода текстовых строк в `<div>`, чтобы мы могли делиться информацией с пользователем.

```js
function wait(delayInMS) {
  return new Promise((resolve) => setTimeout(resolve, delayInMS));
}
```

The `wait()` function returns a new `Promise` which resolves once the specified number of milliseconds have elapsed. It works by using an arrow function which calls `window.setTimeout()` (en-US), specifying the promise's resolution handler as the timeout handler function. That lets us use promise syntax when using timeouts, which can be very handy when chaining promises, as we'll see later.

#### Starting media recording

The `startRecording()` function handles starting the recording process:

```js
function startRecording(stream, lengthInMS) {
  let recorder = new MediaRecorder(stream);
  let data = [];

  recorder.ondataavailable = (event) => data.push(event.data);
  recorder.start();
  log(recorder.state + " for " + lengthInMS / 1000 + " seconds...");

  let stopped = new Promise((resolve, reject) => {
    recorder.onstop = resolve;
    recorder.onerror = (event) => reject(event.name);
  });

  let recorded = wait(lengthInMS).then(
    () => recorder.state == "recording" && recorder.stop(),
  );

  return Promise.all([stopped, recorded]).then(() => data);
}
```

`startRecording()` takes two input parameters: a `MediaStream` to record from and the length in milliseconds of the recording to make. We always record no more than the specified number of milliseconds of media, although if the media stops before that time is reached, `MediaRecorder` automatically stops recording as well.

Line 2

Creates the `MediaRecorder` that will handle recording the input `stream`.

Line 3

Creates an empty array, `data`, which will be used to hold the `Blob`s of media data provided to our `ondataavailable` event handler.

Line 5

Sets up the handler for the `dataavailable` event. The received event's `data` property is a `Blob` that contains the media data. The event handler simply pushes the `Blob` onto the `data` array.

Lines 6-7

Starts the recording process by calling `recorder.start()`, and outputs a message to the log with the updated state of the recorder and the number of seconds it will be recording.

Lines 9-12

Creates a new `Promise`, named `stopped`, which is resolved when the `MediaRecorder`'s `onstop` (en-US) event handler is called, and is rejected if its `onerror` (en-US) event handler is called. The rejection handler receives as input the name of the error that occurred.

Lines 14-16

Creates a new `Promise`, named `recorded`, which is resolved when the specified number of milliseconds have elapsed. Upon resolution, it stops the `MediaRecorder` if it's recording.

Lines 18-22

These lines create a new `Promise` which is fulfilled when both of the two `Promise`s (`stopped` and `recorded`) have resolved. Once that resolves, the array data is returned by `startRecording()` to its caller.

#### Stopping the input stream

The `stop()` function simply stops the input media:

```js
function stop(stream) {
  stream.getTracks().forEach((track) => track.stop());
}
```

This works by calling `MediaStream.getTracks()` (en-US), using `forEach()` to call `MediaStreamTrack.stop()` (en-US) on each track in the stream.

#### Getting an input stream and setting up the recorder

Now let's look at the most intricate piece of code in this example: our event handler for clicks on the start button:

```js
startButton.addEventListener(
  "click",
  function () {
    navigator.mediaDevices
      .getUserMedia({
        video: true,
        audio: true,
      })
      .then((stream) => {
        preview.srcObject = stream;
        downloadButton.href = stream;
        preview.captureStream =
          preview.captureStream || preview.mozCaptureStream;
        return new Promise((resolve) => (preview.onplaying = resolve));
      })
      .then(() => startRecording(preview.captureStream(), recordingTimeMS))
      .then((recordedChunks) => {
        let recordedBlob = new Blob(recordedChunks, { type: "video/webm" });
        recording.src = URL.createObjectURL(recordedBlob);
        downloadButton.href = recording.src;
        downloadButton.download = "RecordedVideo.webm";

        log(
          "Successfully recorded " +
            recordedBlob.size +
            " bytes of " +
            recordedBlob.type +
            " media.",
        );
      })
      .catch(log);
  },
  false,
);
```

When a `click` event occurs, here's what happens:

Lines 2-4

`navigator.mediaDevices.getUserMedia()` (en-US) is called to request a new `MediaStream` that has both video and audio tracks. This is the stream we'll record.

Lines 5-9

When the Promise returned by `getUserMedia()` is resolved, the preview `<video>` element's `srcObject` (en-US) property is set to be the input stream, which causes the video being captured by the user's camera to be displayed in the preview box. Since the `<video>` element is muted, the audio won't play. The "Download" button's link is then set to refer to the stream as well. Then, in line 8, we arrange for `preview.captureStream()` to call `preview.mozCaptureStream()` so that our code will work on Firefox, on which the `MediaRecorder.captureStream()` method is prefixed. Then a new `Promise` which resolves when the preview video starts to play is created and returned.

Line 10

When the preview video begins to play, we know there's media to record, so we respond by calling the `startRecording()` function we created earlier, passing in the preview video stream (as the source media to be recorded) and `recordingTimeMS` as the number of milliseconds of media to record. As mentioned before, `startRecording()` returns a `Promise` whose resolution handler is called (receiving as input an array of `Blob` objects containing the chunks of recorded media data) once recording has completed.

Lines 11-15

The recording process's resolution handler receives as input an array of media data `Blob`s locally known as `recordedChunks`. The first thing we do is merge the chunks into a single `Blob` whose MIME type is `"video/webm"` by taking advantage of the fact that the `Blob()` constructor concatenates arrays of objects into one object. Then `URL.createObjectURL()` is used to create an URL that references the blob; this is then made the value of the recorded video playback element's `src` attribute (so that you can play the video from the blob) as well as the target of the download button's link.

Then the download button's `download` attribute is set. While the `download` attribute can be a Boolean, you can also set it to a string to use as the name for the downloaded file. So by setting the download link's `download` attribute to "RecordedVideo.webm", we tell the browser that clicking the button should download a file named `"RecordedVideo.webm"` whose contents are the recorded video.

Lines 17-18

The size and type of the recorded media are output to the log area below the two videos and the download button.

Line 20

The `catch()` for all the `Promise`s outputs the error to the logging area by calling our `log()` function.

#### Handling the stop button

The last bit of code adds a handler for the `click` event on the stop button using `addEventListener()`:

```js
stopButton.addEventListener(
  "click",
  function () {
    stop(preview.srcObject);
  },
  false,
);
```

This simply calls the `stop()` function we covered earlier.

Result
------

When put all together with the rest of the HTML and the CSS not shown above, it looks and works like this:

You can take a look at all the code, including the parts hidden above because they aren't critical to the explanation of how the APIs are being used.

See also
--------

* MediaStream Recording API
* Using the MediaStream Recording API
* Media Capture and Streams API (en-US)


Использование интерфейса записи медиапотока - Интерфейсы веб API

Использование интерфейса записи медиапотока
===========================================

Интерфейс MediaStream Recording позволяет записывать аудио и видео потоки. При использовании с методом `navigator.mediaDevices.getUserMedia()`, предлагает простой способ записи данных с устройств пользователя, и немедленное их использование в веб приложениях.И аудио и видео могут быть записаны вместе или по отдельности.Цель данной статьи - предоставить базовое руководство о том как использовать объект `MediaRecorder`, реализующий такой программный интерфейс.

Пример приложения: Веб диктофон
-------------------------------

![An image of the Web dictaphone sample app - a sine wave sound visualization, then record and stop buttons, then an audio jukebox of recorded tracks that can be played back.](/ru/docs/Web/API/MediaStream_Recording_API/Using_the_MediaStream_Recording_API/web-dictaphone.png)

Для демонстрации основной функциональности интерфейса `MediaRecorder API`, мы создали веб диктофон, позволяющий записывать отрывки аудио и проигрывать их после записи. Он визуализирует устройства ввода звука, используя интерфейс `Web Audio API`. В этой статье будем концентрироваться на функциональности записи и воспроизведения.

Посмотрите получившуюся работающую демонстрацию, или скачайте исходники на GitHub.

CSS плюшки
----------

Разметка HTML довольно проста, поэтому не будем её рассматривать подробно, но есть более интересные места в CSS, которые стоило бы отметить, и о которых поговорим ниже. Если вам не интересна тема CSS , и хотите сразу приступить к JavaScript, то перейдите к части основных настроек приложения Basic app setup.

### Сохраняйте интерфейс ограниченным областью просмотра, независимо от высоты устройства, с функцией calc()

Функция `calc()` одна из полезных утилит возникших в CSS, которая не выглядеть чем-то выдающимся, но вскоре заставит вас думать о том, почему вы не использовали её раньше?; и почему CSS2 макет такой неуклюжий? Она позволяет выполнять вычисления для определения значений из различных CSS единиц измерений, смешивая их в процессе вычисления.

К примеру, в приложении веб диктофона мы создали три области интерфейса, расположенные вертикально. Первые две имеют фиксированную высоту (заголовок и элементы управления):

```css
header {
  height: 70px;
}

.main-controls {
  padding-bottom: 0.7rem;
  height: 170px;
}
```

Третья область (содержащая записываемые образцы, которые можно воспроизвести) должна занимать оставшуюся от первых двух область, независимо от высоты устройства пользователя. Задача может быть решена, установкой высоты третьей области равной 100% родительской высоты, минус высоты и отступы первых двух.

```css
.sound-clips {
  box-shadow: inset 0 3px 4px rgba(0, 0, 0, 0.7);
  background-color: rgba(0, 0, 0, 0.1);
  height: calc(100% - 240px - 0.7rem);
  overflow: scroll;
}
```

**Примечание:** Функция `calc()` имеет хорошую поддержку среди современных браузеров, даже в устаревшем Internet Explorer 9.

### Хак чекбокса для отображение/скрытия

Он уже хорошо документирован, но думаем его можно упомянуть, заключающийся в том, что можно кликнуть на элемент `<label>` , содержащий элемент чекбокса для переключения самого чекбокса. В нашем приложении веб диктофона он управляет отображением блока информации о приложении, при нажатии на иконку знака вопроса в правом верхнем углу. Сначала мы стилизуем элемент `<label>` , тем, что мы хотим, убеждаясь в том, что он имеет достаточно высокий `z-index` , всегда находящийся выше других элементов :

```css
label {
  font-family: "NotoColorEmoji";
  font-size: 3rem;
  position: absolute;
  top: 2px;
  right: 3px;
  z-index: 5;
  cursor: pointer;
}
```

Затем скрываем настоящий чекбокс, избегая неразберихи в интерфейсе :

```css
input[type="checkbox"] {
  position: absolute;
  top: -100px;
}
```

Затем стилизуем блок информации (обёрнутый в элемент `<aside>`) по вкусу, давая ему фиксированную позицию, так что бы он не показывался в потоке разметки и влиял на основной интерфейс, трансформируем его позицию функцией трансформации, определяя его место по умолчанию, и меняем значение функции трансформации для плавного его отображения/скрытия:

```css
aside {
  position: fixed;
  top: 0;
  left: 0;
  text-shadow: 1px 1px 1px black;
  width: 100%;
  height: 100%;
  transform: translateX(100%);
  transition: 0.6s all;
  background-color: #999;
  background-image: linear-gradient(
    to top right,
    rgba(0, 0, 0, 0),
    rgba(0, 0, 0, 0.5)
  );
}
```

Наконец определяем правило при нажатии чекбокса . Когда он выбран (когда нажат элемент `label`) соседний элемент `<aside>` получит значение горизонтального перехода и переместится в представление:

```css
input[type="checkbox"]:checked ~ aside {
  transform: translateX(0);
}
```

Основные настройки приложения
-----------------------------

Для получения медиапотока, который нужно захватить используется метод `getUserMedia()`. Затем используется интерфейс `MediaRecorder`, для записи потока и вывода каждого отрывка записи в атрибут элемента `<audio>` для воспроизведения.

Объявим некоторые переменные для кнопок начала записи и остановки, а так же элемент `<article>` , который будет содержать аудио плееры:

```js
const record = document.querySelector(".record");
const stop = document.querySelector(".stop");
const soundClips = document.querySelector(".sound-clips");
```

Наконец, для этого раздела создадим базовую структуру `getUserMedia` :

```js
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
  console.log("getUserMedia supported.");
  navigator.mediaDevices
    .getUserMedia(
      // Установим ограничение на получение только аудио потока
      {
        audio: true,
      },
    )
    // Функция успешного получения потока
    .then(function (stream) {})
    // Функция ошибок
    .catch(function (err) {
      console.log("The following getUserMedia error occured: " + err);
    });
} else {
  console.log("getUserMedia not supported on your browser!");
}
```

Все обёрнуто в условный тест, проверяющий поддержку `getUserMedia` до запуска чего нибудь. Затем вызываем `getUserMedia()` и внутри определяем:

* **Ограничения** : Приложению нужен только аудиопоток .
* **Функция успешного вызова**: Запускается при успешном получении потока функцией `getUserMedia` .
* **Функция обработки ошибок**: Если функция `getUserMedia` по какой либо причине завершиться с ошибкой.

**Примечание:** Весь код ниже помещается внутрь функции успешного вызова `getUserMedia.`

Захват медиа потока
-------------------

Как только функция `getUserMedia` успешно получила медиапоток, создаём новый объект типа Media Recorder конструктором `MediaRecorder()` и передаём ему поток, полученный функцией. Это точка входа использования интерфейса MediaRecorder — теперь поток готов для захвата и упаковки в объект `Blob`, в формате по умолчанию, установленного для браузера.

```js
const mediaRecorder = new MediaRecorder(stream);
```

Существуют несколько методов объекта `MediaRecorder` , позволяющие контролировать запись медиапотока; в приложении веб диктофон используется два и прослушиваем некоторые события. Прежде всего используем метод `MediaRecorder.start()` , для запуска записи потока, после нажатия кнопки старта:

```js
record.onclick = function () {
  mediaRecorder.start();
  console.log(mediaRecorder.state);
  console.log("recorder started");
  record.style.background = "red";
  record.style.color = "black";
};
```

Когда объект `MediaRecorder` приступает к записи его свойство `MediaRecorder.state` получает значение "`recording`".

По мере записи, нам нужно получать аудио данные. Для этого регистрируем обработчик события `mediaRecorder.ondataavailable`:

```js
let chunks = [];

mediaRecorder.ondataavailable = function (e) {
  chunks.push(e.data);
};
```

**Примечание:** Браузер будет запускать события `dataavailable` по необходимости (когда внутренний буфер объекта будет переполняться), но если разработчику нужно вмешаться, в вызов метода `start()` можно включить параметр `timeslice`, определяющий диапазон захвата в миллисекундах — к примеру, `start(10000)`, или вызывать функцию запроса данных `MediaRecorder.requestData()`, запуская событие по необходимости.

Наконец используем метод `MediaRecorder.stop()` (en-US) при нажатии кнопки остановки записи и завершения упаковки объекта `Blob` для его использования в приложении.

```js
stop.onclick = function () {
  mediaRecorder.stop();
  console.log(mediaRecorder.state);
  console.log("recorder stopped");
  record.style.background = "";
  record.style.color = "";
};
```

Обратите внимание, что запись потока может остановиться естественно, если медиапоток кончился(к примеру, если захватывается музыкальный трек и он кончился, или пользователь отключил использование микрофона, чей поток захватывается).

Получение и использования объекта blob
--------------------------------------

Когда запись останавливается, свойство `state` получает значение "`inactive`", и запускается событие `stop`. Мы устанавливаем обработчик этого события, используя свойство `mediaRecorder.onstop` (en-US), завершая запись всех полученных порций объекта `blob` на момент остановки:

```js
mediaRecorder.onstop = function (e) {
  console.log("recorder stopped");

  const clipName = prompt("Enter a name for your sound clip");

  const clipContainer = document.createElement("article");
  const clipLabel = document.createElement("p");
  const audio = document.createElement("audio");
  const deleteButton = document.createElement("button");

  clipContainer.classList.add("clip");
  audio.setAttribute("controls", "");
  deleteButton.innerHTML = "Delete";
  clipLabel.innerHTML = clipName;

  clipContainer.appendChild(audio);
  clipContainer.appendChild(clipLabel);
  clipContainer.appendChild(deleteButton);
  soundClips.appendChild(clipContainer);

  const blob = new Blob(chunks, { type: "audio/ogg; codecs=opus" });
  chunks = [];
  const audioURL = window.URL.createObjectURL(blob);
  audio.src = audioURL;

  deleteButton.onclick = function (e) {
    let evtTgt = e.target;
    evtTgt.parentNode.parentNode.removeChild(evtTgt.parentNode);
  };
};
```

Пройдём весь код выше и посмотрим, что он делает.

Сначала отображаем пользователю диалог с запросом имени будущей записи.

Затем создаём структуру HTML , вставляя её в контейнер, представляющийся элементом `<article>` .

```html
<article class="clip">
  <audio controls></audio>
  <p>your clip name</p>
  <button>Delete</button>
</article>
```

После этого создаём объект `Blob` с комбинацией наших записанных частей аудио и создаём объект URL ссылающийся на него, используя метод `window.URL.createObjectURL(blob)`. Затем устанавливаем значение атрибута `src` элемента `<audio>` в созданный объект URL, так, что бы при нажатии на кнопку воспроизведения объект `Blob` передал свои данные элементу.

Наконец, устанавливаем обработчик события `onclick` на кнопке удаления, для удаления всей структуры HTML проигрывания результата записи (элемент clip).

Спецификации
------------

| Specification |
| --- |
| MediaStream Recording # mediarecorder-api |

Совместимость с браузерами
--------------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Смотрите также
--------------

* Страница MediaRecorder API (en-US)
* ``Navigator.getUserMedia()``
* Интерфейс MediaRecorder теперь поддерживают 65% веб-сайтов


CacheStorage.match() - Интерфейсы веб API

CacheStorage.match()
====================

**Экспериментальная возможность:** **Это экспериментальная технология**
Так как спецификация этой технологии ещё не стабилизировалась, смотрите таблицу совместимости по поводу использования в различных браузерах. Также заметьте, что синтаксис и поведение экспериментальной технологии может измениться в будущих версиях браузеров, вслед за изменениями спецификации.

Метод **`match()`** интерфейса `CacheStorage` (доступный через глобальное свойство `caches`) проверяет является ли данный `Request` или строка url ключом для какого-либо хранимого `Response`. Метод возвращает `Promise` если `Response` найден, или `undefined` если нет ни одного совпадения.

Объекты Cache проверяются в порядке создания.

**Примечание:** `caches.match()` это метод для удобства в работе. Такая функциональность достигается вызовом `cache.match()` для каждого объекта cache (в порядке полученном запросом `caches.keys()` (en-US)) пока `Response` не будет найден.

Синтаксис
---------
```

caches.match(request, options).then(function(response) {
  // Какие-либо действия с response
});
```

### Параметры

request

`Request` для поиска. Может быть объектом `Request` или строкой URL.

options Необязательный

Объект, свойства которого определяют, как проверяется совпадение в операции сопоставления. Доступны следующие варианты:

* `ignoreSearch`: `Boolean` (en-US) свойство. Определяет, следует ли игнорировать параметры запроса в строке url или нет. Например, если установлено `true`, параметры `?value=bar` запроса `http://foo.com/?value=bar` будут проигнорированы во время сопоставления. Значением по умолчанию является `false`.
* `ignoreMethod`: `Boolean` (en-US) свойство. Когда установлено `true`, предотвращает проверку `http` метода запроса `Request` (обычно разрешены только `GET` и `HEAD`.) По умолчанию установлено `false`.
* `ignoreVary`: `Boolean` (en-US) свойство, определяющее, следует ли выполнять проверку заголовка `VARY.` Если установлено `true`, совпадения будут найдены, независимо от того, имеет ли `Response` заголовок `VARY` или нет. По умолчанию установлено `false`.
* `cacheName`: Строка `DOMString` - имя кеша для поиска.

### Возвращаемое значение

Метод возвращает `Promise` который разрешается совпавшим `Response`. Если ни одного совпадений не было найдено, promise разрешается с `undefined`.

Примеры
-------

Это пример из MDN sw-test example (см. sw-test running live). В данном примере, мы обрабатываем событие `FetchEvent`. Мы строим проверку ответа следующим образом:

1. Проверяем, совпадения для запроса в `CacheStorage` используя `CacheStorage.match()`. Если совпадение найдено, возвращаем response.
2. Если нет, открываем `v1` объект кеша, используя метод `open()`, добавляем изначальный запрос в кеш используя `Cache.put()` (en-US) и возвращаем клонированный объект запроса, используя `return response.clone()`. Это необходимо, потому что метод `put()` сохраняет в кеш тело запроса, изменяя, таким образом, изначальный запрос.
3. Если произошла какая-либо ошибка (например, из-за проблем с сетью), возвращаем резервный ответ.

```js
caches
  .match(event.request)
  .then(function (response) {
    return (
      response ||
      fetch(event.request).then(function (r) {
        caches.open("v1").then(function (cache) {
          cache.put(event.request, r);
        });
        return r.clone();
      })
    );
  })
  .catch(function () {
    return caches.match("/sw-test/gallery/myLittleVader.jpg");
  });
```

Спецификации
------------

| Specification |
| --- |
| Service Workers # cache-storage-match |

Совместимость с браузерами
--------------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Смотрите также
--------------

* Использование Service Workers (en-US)
* `Cache`
* `self.caches` (en-US)


CacheStorage.open() - Интерфейсы веб API

CacheStorage.open()
===================

**Экспериментальная возможность:** **Это экспериментальная технология**
Так как спецификация этой технологии ещё не стабилизировалась, смотрите таблицу совместимости по поводу использования в различных браузерах. Также заметьте, что синтаксис и поведение экспериментальной технологии может измениться в будущих версиях браузеров, вслед за изменениями спецификации.

**`open()`** метод из `CacheStorage` интерфейса возвращает `Promise` который резолвится в `Cache` объект с соответствующим `cacheName (именем тега кеша)`.

**Примечание:** If the specified `Cache` does not exist, a new cache is created with that `cacheName`.

Синтаксис
---------
```

caches.open(cacheName).then(function(cache) {
  //обрабатываем кеш например: cache.AddAll(filesToCache); где filesToCache = ['/mypic.png', ...]
});
```

### Возвращает

`Promise` который резолвится в запрашиваемый `Cache` объект.

### Параметры

cacheName

Имя (тег) кеша заданное заранее которое необходимо открыть.

Примеры
-------

This code snippet is from the MDN sw-test example (see sw-test running live). Here we wait for a `FetchEvent` to fire. Then we construct a custom response like so:

1. Check whether a match for the request is found in the `CacheStorage` using `CacheStorage.match`. If so, serve that.
2. If not, open the `v1` cache using `CacheStorage.open`, put the default network request in the cache using `Cache.put` (en-US) and return a clone of the default network request using `return response.clone()` — necessary because `put()` consumes the response body.
3. If this fails (e.g., because the network is down), return a fallback response.

```js
var response;
var cachedResponse = caches
  .match(event.request)
  .catch(function () {
    return fetch(event.request);
  })
  .then(function (r) {
    response = r;
    caches.open("v1").then(function (cache) {
      cache.put(event.request, response);
    });
    return response.clone();
  })
  .catch(function () {
    return caches.match("/sw-test/gallery/myLittleVader.jpg");
  });
```

Specifications
--------------

| Specification |
| --- |
| Service Workers # cache-storage-open |

Совместимость с браузерами
--------------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* Using Service Workers (en-US)
* `Cache`
* `WorkerGlobalScope.caches` (en-US)


ServiceWorkerRegistration.update() - Интерфейсы веб API

ServiceWorkerRegistration.update()
==================================

**Экспериментальная возможность:** **Это экспериментальная технология**
Так как спецификация этой технологии ещё не стабилизировалась, смотрите таблицу совместимости по поводу использования в различных браузерах. Также заметьте, что синтаксис и поведение экспериментальной технологии может измениться в будущих версиях браузеров, вслед за изменениями спецификации.

Метод **`update`** интерфейса `ServiceWorkerRegistration` предназначен для обновления service worker. Он обращается по URL service worker-a, и если новый worker побайтно не совпадает с текущим, инсталлирует новую версию. Обращение за новой версией worker обходит любые кеши браузера, если предыдущее обращение произошло более 24 часов назад..

**Примечание:** Эта возможность доступна в Web Workers.

Синтаксис
---------
```

ServiceWorkerRegistration.update();
```

### Параметры

Нет.

### Возвращает

`Промис`, который разрешается в объект `ServiceWorkerRegistration`.

Пример
------

В следующем простом примере регистрируется service worker, а затем добавляется обработчик события клика по кнопке, так что вы можете явно обновить service worker по необходимости:

```js
if ("serviceWorker" in navigator) {
  navigator.serviceWorker
    .register("/sw-test/sw.js", { scope: "sw-test" })
    .then(function (registration) {
      // Регистрация произошла
      console.log("Registration succeeded.");
      button.onclick = function () {
        registration.update();
      };
    })
    .catch(function (error) {
      // Ошибка при регистрации
      console.log("Registration failed with " + error);
    });
}
```

Спецификации
------------

| Specification |
| --- |
| Service Workers # service-worker-registration-update |

Совместимость с браузерами
--------------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Смотрите также
--------------

* Использование Service Workers (en-US)
* Service workers базовый пример кода
* Готов ли ServiceWorker?
* `Промисы`
* Использование web workers (en-US)


ServiceWorkerRegistration.showNotification() - Интерфейсы веб API

ServiceWorkerRegistration.showNotification()
============================================

**Экспериментальная возможность:** **Это экспериментальная технология**
Так как спецификация этой технологии ещё не стабилизировалась, смотрите таблицу совместимости по поводу использования в различных браузерах. Также заметьте, что синтаксис и поведение экспериментальной технологии может измениться в будущих версиях браузеров, вслед за изменениями спецификации.

The `showNotification()` method of the `ServiceWorkerRegistration` interface creates a notification on an active service worker.

**Примечание:** This feature is available in Web Workers.

Syntax
------
```

ServiceWorkerRegistration.showNotification(title, [options]).then(function(NotificationEvent) { ... });
```

### Returns

A `Promise` that resolves to a `NotificationEvent` (en-US).

### Parameters

`title`

The title that must be shown within the notification

`options` Необязательный

An object that allows to configure the notification. It can have the following properties:

* `actions`: An array of actions to display in the notification. The members of the array should be an object literal. It may contain the following values:
    + action: A `DOMString` identifying a user action to be displayed on the notification.
    + title: A `DOMString` containing action text to be shown to the user.
    + icon: A `USVString` (en-US) containg the URL of an icon to display with the action.Appropriate responses are built using `event.action` within the `notificationclick` event.
* `badge`: The URL of an image to represent the notification when there is not enough space to display the notification itself such as, for example, the Android Notification Bar. On Android devices, the badge should accommodate devices up to 4x resolution, about 96 by 96 px, and the image will be automatically masked.
* `body`: Строка с дополнительным контентом уведомления.
* `dir` : The direction of the notification; it can be `auto`, `ltr`, or `rtl`
* `icon`: URL или base64 версия картинки, которая отображается рядом с уведомлением.
* `image`: URL `USVSTring` (en-US) картинки, которая отображается внутри уведомления.
* `lang`: Specify the lang used within the notification. This string must be a valid BCP 47 language tag.
* `renotify`: A boolean that indicates whether to supress vibrations and audible alerts when resusing a `tag` value. The default is false.
* `requireInteraction`: Indicates that on devices with sufficiently large screens, a notification should remain active until the user clicks or dismisses it. If this value is absent or false, the desktop version of Chrome will auto-minimize notifications after approximately twenty seconds. The default value is `false`.
* `tag`: An ID for a given notification that allows you to find, replace, or remove the notification using script if necessary.
* `vibrate`: Шаблон вибрации, которая будет воспроизведена вместе с уведомлением. Шаблон может быть массивом из как минимум одного элемента. Значения элементов это время в миллисекундах, при этом чётные элементы (0, 2, 4, и т.д.) отражают периоды вибрации, а нечётные периоды пауз. Например, `[300, 100, 400]` будет означать вибрацию 300ms, паузу 100ms, затем вибрацию 400ms.
* `data`: Arbitrary data that you want associated with the notification. This can be of any data type.

Examples
--------

```js
navigator.serviceWorker.register("sw.js");

function showNotification() {
  Notification.requestPermission(function (result) {
    if (result === "granted") {
      navigator.serviceWorker.ready.then(function (registration) {
        registration.showNotification("Vibration Sample", {
          body: "Buzz! Buzz!",
          icon: "../images/touch/chrome-touch-icon-192x192.png",
          vibrate: [200, 100, 200, 100, 200, 100, 200],
          tag: "vibration-sample",
        });
      });
    }
  });
}
```

To invoke the above function at an appropriate time, you could use the `ServiceWorkerGlobalScope.onnotificationclick` event handler.

You can also retrieve details of the `Notification`s have have been fired from the current service worker using `ServiceWorkerRegistration.getNotifications()` (en-US).

Specifications
--------------

| Specification |
| --- |
| Notifications API Standard # dom-serviceworkerregistration-shownotification |

Совместимость с браузерами
--------------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


ServiceWorkerRegistration.pushManager - Интерфейсы веб API

ServiceWorkerRegistration.pushManager
=====================================

**Экспериментальная возможность:** **Это экспериментальная технология**
Так как спецификация этой технологии ещё не стабилизировалась, смотрите таблицу совместимости по поводу использования в различных браузерах. Также заметьте, что синтаксис и поведение экспериментальной технологии может измениться в будущих версиях браузеров, вслед за изменениями спецификации.

Свойство **`pushManager`** интерфейса `ServiceWorkerRegistration` возвращает ссылку на интерфейс `PushManager`, позволяющий управлять подписками на push-уведомления. Включает поддержку процедуры подписки, получения активной подписки, а также предоставляет доступ к статусу разрешений на push-уведомления.

Синтаксис
---------
```

myPushManager = ServiceWorker.pushManager
```

### Значение

Объект `PushManager`.

Примеры
-------

```js
this.onpush = function (event) {
  console.log(event.data);
  // Отсюда можно записывать данные в IndexedDB, отправлять их в любое
  // открытое окно, отображать уведомление и т. д.
};

navigator.serviceWorker
  .register("serviceworker.js")
  .then(function (serviceWorkerRegistration) {
    serviceWorkerRegistration.pushManager.subscribe().then(
      function (pushSubscription) {
        console.log(pushSubscription.subscriptionId);
        console.log(pushSubscription.endpoint);
        // Детали push-подписки, требуемые сервером приложения,
        // теперь доступны, и могут быть отправлены, к примеру,
        // при помощи XMLHttpRequest.
      },
      function (error) {
        // При разработке это часто помогает отлавливать ошибки в консоли.
        // В продакшен-среде это также может быть полезно для отправки отчёта
        // об ошибках на сервер приложения.
        console.log(error);
      },
    );
  });
```

Спецификации
------------

| Specification |
| --- |
| Push API # dom-serviceworkerregistration-pushmanager |

Совместимость с браузерами
--------------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Смотрите также
--------------

* Push API


USB.onconnect - Интерфейсы веб API

USB.onconnect
=============

Limited availability
--------------------

This feature is not Baseline because it does not work in some of the most widely-used browsers.

* Learn more
* See full compatibility
* Report feedback
**Экспериментальная возможность:** **Это экспериментальная технология**
Так как спецификация этой технологии ещё не стабилизировалась, смотрите таблицу совместимости по поводу использования в различных браузерах. Также заметьте, что синтаксис и поведение экспериментальной технологии может измениться в будущих версиях браузеров, вслед за изменениями спецификации.

**Secure context:** This feature is available only in secure contexts (en-US) (HTTPS), in some or all supporting browsers.

Свойство **`onconnect`** интерфейса `USB` является обработчиком события, который вызывается всегда, когда сопряжённое устройство подключается.

Синтаксис
---------
```

USB.onconnect = connectFunction
```

Спецификации
------------

| Specification |
| --- |
| WebUSB API # connect |
| WebUSB API # ref-for-dom-usb-onconnect |

Совместимость с браузерами
--------------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


USB.getDevices() - Интерфейсы веб API

USB.getDevices()
================

Limited availability
--------------------

This feature is not Baseline because it does not work in some of the most widely-used browsers.

* Learn more
* See full compatibility
* Report feedback
**Экспериментальная возможность:** **Это экспериментальная технология**
Так как спецификация этой технологии ещё не стабилизировалась, смотрите таблицу совместимости по поводу использования в различных браузерах. Также заметьте, что синтаксис и поведение экспериментальной технологии может измениться в будущих версиях браузеров, вслед за изменениями спецификации.

**Secure context:** This feature is available only in secure contexts (en-US) (HTTPS), in some or all supporting browsers.

Метод\*\* `getDevices` \*\*интерфейса `USB` возвращает `Promise`, который разрешается с массивом `USBDevice` (en-US) объектов сопряжённых подключённых устройств. Для информации о сопряжённых устройствах, смотрите `USB.requestDevice()`.

Синтаксис
---------
```

USB.getDevices()
```

### Параметры

Нет.

### Возвращаемое значение

`Promise`, который разрешается с массивом объектов `USBDevice` (en-US).

Пример
------

В следующем примере имена продуктов и серийные номера сопряжённых устройств выводятся в консоль. Для информации о сопряжённых устройствах, смотрите `USB.requestDevice()`.

```js
navigator.usb.getDevices().then((devices) => {
  console.log("Total devices: " + devices.length);
  devices.forEach((device) => {
    console.log(
      "Product name: " +
        device.productName +
        ", serial number " +
        device.serialNumber,
    );
  });
});
```

Спецификация
------------

| Specification |
| --- |
| WebUSB API # ref-for-dom-usb-getdevices② |

Совместимость с браузерами
--------------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


USB.requestDevice() - Интерфейсы веб API

USB.requestDevice()
===================

Limited availability
--------------------

This feature is not Baseline because it does not work in some of the most widely-used browsers.

* Learn more
* See full compatibility
* Report feedback
**Экспериментальная возможность:** **Это экспериментальная технология**
Так как спецификация этой технологии ещё не стабилизировалась, смотрите таблицу совместимости по поводу использования в различных браузерах. Также заметьте, что синтаксис и поведение экспериментальной технологии может измениться в будущих версиях браузеров, вслед за изменениями спецификации.

**Secure context:** This feature is available only in secure contexts (en-US) (HTTPS), in some or all supporting browsers.

Метод **`requestDevice()`** интерфейса `USB` возвращает `Promise`, возвращающий экземпляр `USBDevice` (en-US), если необходимое устройство было найдено. Вызов этого метода начинает процесс соединения браузера с устройством.

Синтаксис
---------
```

USB.requestDevice([filters])
```

### Параметры

filters

Массив объектов, определяющих фильтры для устройств, к которым требуется подключиться. Каждый фильтр может содержать следующие свойства:

* `vendorId` - ИД производителя (USB VID)
* `productId` - ИД устройства USB PID
* `classCode` - код класса функциональности устройства
* `subclassCode` - код подкласса
* `protocolCode` - код протокола
* `serialNumber` - серийный номер

### Возвращаемое значение

`Promise`, возвращающий экземпляр `USBDevice` (en-US).

Пример
------

Этот пример запрашивает любое из перечисленных USB-устройств. Обратите внимание, указаны два разных PID. Оба присутствуют в списке фильтров для `requestDevice()`. При этом браузер покажет окно для выбора и подтверждения доступа к устройству. Только выбранное пользователем устройство будет передано в `then()`.

Количество фильтров не определяет количество устройств, показываемых браузером. Например, если найдено только USB-устройство с product ID `0xa800`, браузер отобразит только одно устройство. Но, если браузер определит два устройства, совпадающих с первым фильтром, и ещё одно, совпадающее со вторым, будут показаны все три устройства.

```js
const filters = [
  { vendorId: 0x1209, productId: 0xa800 },
  { vendorId: 0x1209, productId: 0xa850 },
];
navigator.usb
  .requestDevice({ filters: filters })
  .then((usbDevice) => {
    console.log("Product name: " + usbDevice.productName);
  })
  .catch((e) => {
    console.log("There is no device. " + e);
  });
```

Спецификации
------------

| Specification |
| --- |
| WebUSB API # ref-for-dom-usb-requestdevice④ |

Совместимость с браузерами
--------------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


USB.ondisconnect - Интерфейсы веб API

USB.ondisconnect
================

Limited availability
--------------------

This feature is not Baseline because it does not work in some of the most widely-used browsers.

* Learn more
* See full compatibility
* Report feedback
**Экспериментальная возможность:** **Это экспериментальная технология**
Так как спецификация этой технологии ещё не стабилизировалась, смотрите таблицу совместимости по поводу использования в различных браузерах. Также заметьте, что синтаксис и поведение экспериментальной технологии может измениться в будущих версиях браузеров, вслед за изменениями спецификации.

**Secure context:** This feature is available only in secure contexts (en-US) (HTTPS), in some or all supporting browsers.

Свойство **`ondisconnect`** интерфейса `USB` является обработчиком события, который вызывается всегда, когда сопряжённое устройство отключается.

Синтаксис
---------
```

USB.ondisconnect = disconnectFunction
```

Спецификации
------------

| Specification |
| --- |
| WebUSB API # disconnect |
| WebUSB API # ref-for-dom-usb-ondisconnect |

Совместимость с браузерами
--------------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.