Версия 2.1
«Не разводите сырость»
Александр Сушко

Сырые данные — это...
Сырые данные — это данные,
которые не были проанализированы,
закодированы или преобразованы 
Сырые данные, в нашем случае,—
это содержимое файлов
BLOB
Binary Large Object
Массив бинарных данных.
Иначе — двоичных
FileAPI
Определяет, как нам работать
с содержимым файлов
прямо в браузере
Пересказ
История...

<?xml version="1.0" encoding="windows-1251"?>
<Файл xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ИдФайл="ON_DOCNPNO_6321422260632101001_6321422260632101001_0093_20180704_f9123170cc014fe5bff51ccbb10f8aa6" ВерсПрог="Налог3-А" ВерсФорм="5.01" xsi:noNamespaceSchemaLocation="ON_DOCNPNO_1_886_00_05_01_01.xsd">
  <Документ КНД="1184002" ДатаДок="28.12.2017">
    <СвОтпрДок>
      <ОтпрНО КодНО="0093" НаимНО="0093" />
    </СвОтпрДок>
    <СвПолДок>
      <ОтпрЮЛ НаимОрг="ООО "ШУЛЕР СЕРВИС РУС"" ИННЮЛ="6321422260" КПП="632101001" />
    </СвПолДок>
    <СвНП>
      <НПЮЛ НаимОрг="ООО "ШУЛЕР СЕРВИС РУС"" ИННЮЛ="6321422260" КПП="632101001" />
    </СвНП>
    <Подписант Должн="Руководитель">
      <ФИО Фамилия="Reg" Имя="Ofd" Отчество="Test" />
    </Подписант>
    <ДокНапрИзНО ИдФайлЗаяв="KO_ZVLREGKKT_0093_0093_6321422260632101001_20180704_defd99c90e3e4035809c666366675770">
      <ИнфСообДок КНД_Док="1110211" НомФайлДок="167897" ДатаФайлДок="28.12.2017" КолФайл="1">
        <ИмяФайл>1110211_0093_6321422260632101001_2b4edfd4-d702-4a6e-91e4-20d06731e178_20180704_2b4edfd4-d702-4a6e-91e4-20d06731e178</ИмяФайл>
      </ИнфСообДок>
      <ИнфСообДок КНД_Док="1110211" НомФайлДок="167897" ДатаФайлДок="28.12.2017" КолФайл="1">
        <ИмяФайл>1110211_0093_6321422260632101001_3a3dde30-6c64-43ff-b129-79b0c471dee3_20180704_3a3dde30-6c64-43ff-b129-79b0c471dee3</ИмяФайл>
      </ИнфСообДок>
    </ДокНапрИзНО>
  </Документ>
</Файл>

Нюанс
Фронтенд
Бэкенд
«Принтер»
Фронтенд
Бэкенд
«Принтер»
Скачать документ
Подготавливаем документ
...
fetch("/api")
  .then(function(response) {
    return response.json();
  })
  .then(function(data) {
    window.location.href = data.fileUrl;
  });
PROFIT
// console.log(response);
{
  type: "application/pdf",
  size: 12345,
  fileContent: "SGVsbG8sIHdvcmxkIQ..."
}
Wat?
// console.log(response);
{
  type: "application/pdf",
  size: 12345,
  fileContent: "SGVsbG8sIHdvcmxkIQ..."
}
public class Print
{
  public Guid Id { get; set; }
  public string Type { get; set; }
  
  public int Size { get; set; }
  
  public byte[] FileContent { get; set; }
}
Base64? M-m-m...
fetch("/api")
  .then(function(response) {
    return response.json();
  })
  .then(function(data) {
    const { type, fileContent } = data;
    window.location.href =
      `data:${type};base64,${fileContent}`;
  });
Fuck yeah!

IE и Base64
Ограничение в 32,768 символов
«Только» картинки
Свои требования к кодированию спец.символов
–
–
–

async function downloadFile(filename) {
  const { content, type } = await api.getFile();
  const blob = new Blob([content], { type: type });
  if (isMsBlob) {
    window.navigator.msSaveBlob(blob, filename);
  } else {
    const link = document.createElement("a");
    link.href = window.URL.createObjectURL(blob);
    link.download = filename;
    document.body.appendChild(link);
    link.click();
    setTimeout(function() {
      window.URL.revokeObjectURL(link.href);
      document.body.removeChild(link);
    }, 0);
  }
}const binString = window.atob(content);
const buffer =
  new Uint8Array(binString.length);
for (let i = 0; i < binString.length; i++) {
  buffer[i] = binString.charCodeAt(i);
}
const blob = new Blob([buffer], { type });Ctrl + C Ctrl + V
async function download(filename) {
  const { content, type } = await api.getFile();
  const binString = window.atob(content);
  const buffer = new Uint8Array(binString.length);
  for (let i = 0; i < binString.length; i++) {
    buffer[i] = binString.charCodeAt(i);
  }
  const blob = new Blob([buffer], { type: type });
  if (isMsBlob) {
    window.navigator.msSaveBlob(blob, filename);
  } else {
    const link = document.createElement("a");
    link.href = window.URL.createObjectURL(blob);
    link.download = filename;
    document.body.appendChild(link);
    link.click();
    setTimeout(function() {
      window.URL.revokeObjectURL(link.href);
      document.body.removeChild(link);
    }, 0);
  }
}
PROFIT
FileAPI
FileAPI это...
Определяет, как нам работать
с содержимым файлов
прямо в браузере
История
2006 – First Public Draft
2009 – Working Draft
2013 – Last Call
2017 – снова Working Draft
Поддержка
Firefox, Chrome, Safari
Edge 16+ (с оговоркой)
IE 10+ (с оговорками)
–
–
–
FileAPI
FileList и File
FileReader
Blob
–
–
–
Методы расширения window.URL
–
FileList и File
FileList
FileList – список File.
const files =
  document.querySelector("[type=\"file\"]").files;Всё!
for (let file of files) { /*...*/ }files.item(0);
File
Содержимое с метаданными
о файле.
{
  lastModified,
  lastModifiedDate,
  name
}File
const file = new File(blob, filename, options);Оговорка: IE и Edge не умеют
Содержимое с метаданными
о файле.
It's demo time!
blob:
blob:
Ссылка на содержимое.
blob:https://example.org/9115d58c-bcda-ff47-86e5...blob:
Ссылка на содержимое.
/* Создание */
const link =
  window.URL.createObjectURL( file || blob );
/* Удаление */
window.URL.revokeObjectURL(link);blob:
Ссылка живёт в рамках document
Не хранит в себе данных
–
–
It's demo time!
FileReader
FileReader
Позволяет читать содержимое файлов.
const filereader = new FileReader();
filereader.readAsText( file || blob );FileReader
Умеет в асинхронность
Можно прервать чтение
–
–
Умеет показывать прогресс
–
It's demo time!
Blob
Blob
Объект, содержащий бинарные данные, сырые и неизменяемые.
const blob = new Blob(
  [ blob || arrayBuffer || string ],
  { type, endings }
);
blob.slice( start, end, type );It's demo time!
Blob и xhr, level 2
xhr.responseType = "blob";
xhr.addEventListener("load", function() {
  html5player.srcObject = xhr.response;
});
Blob и fetch
fetch("/video-stream.php")
  .then(function(response) {
    return response.blob();
  })
  .then(function(blob) {
    html5player.srcObject = blob;
  });Blob и Canvas
const canvas = document.querySelector("canvas");
canvas.toBlob(function(blob) {
  const link = window.URL.createObjectURL(blob);
  image.src = link;
  image.addEventListener("load", function() {
    window.URL.revokeObjectURL(link);
  });
});
It's demo time!
Нюансы Blob
Размер Blob ограничен
IE умеет Blob, но по своему
–
–
const link = document.createElement("a");
link.href = window.URL.createObjectURL(blob);
link.download = filename;
document.body.appendChild(link);
link.click();
setTimeout(function() {
  window.URL.revokeObjectURL(link.href);
  document.body.removeChild(link);
}, 0);
window.navigator.msSaveBlob(blob, filename);
/* или */
window.navigator.msSaveOrOpenBlob(blob, filename);Так причём здесь сырость?
async function download(filename) {
  const response = await api.getFile();
  const binString = window.atob(response.content);
  const buffer = new Uint8Array(binString.length);
  for (let i = 0; i < binString.length; i++) {
    buffer[i] = binString.charCodeAt(i);
  }
  const blob = new Blob([buffer], { type: response.type });
  if (isMsBlob) {
    window.navigator.msSaveBlob(blob, filename);
  } else {
    const link = document.createElement("a");
    link.href = window.URL.createObjectURL(blob);
    link.download = filename;
    document.body.appendChild(link);
    link.click();
    setTimeout(function() {
      window.URL.revokeObjectURL(link.href);
      document.body.removeChild(link);
    }, 0);
  }
}Фронтенд
Бэкенд
«Принтер»
Фронтенд
Бэкенд
«Принтер»
Хранилище
Сервер – бог,
браузер – лох

Александр Сушко
Фронтенд-разработчик, СКБ Контур
Вопросы?
Ссылки
TypedArray
wiki.amperka.ru/js:typedarray
2ality.com/2015/09/typed-arrays.html
 
Working With Files in JavaScript
blog.brew.com.hk/working-with-files-in-javascript
 
Bytes and Blobs
Секретный раздел
ArrayBuffer
Контейнер определенной длины для хранения двоичных данных
Массив в истинном его понимании
Не поддерживает чтение или запись
–
–
–
TypedArray
Массивоподобное представление буфера с бинарными данными.
Существует «на словах».
Способы отображения

Не разводите сырость 2.1
By Alexander Sushko
Не разводите сырость 2.1
Версия презентации для IzhTechTalks по фронтенду, 30 августа
- 1,341
 
   
   
  