@@ -0,0 +1,63 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="720" height="1080" viewBox="0 0 720 1080" role="img" aria-labelledby="title desc">
|
||||
<title id="title">Диагностика идентичности ES-модулей по URL</title>
|
||||
<desc id="desc">Верхняя панель показывает два import одного URL init.js и одну module identity. Нижняя панель показывает init.js и init.js с query как две разные identity. Внизу указан порядок проверки.</desc>
|
||||
<defs>
|
||||
<linearGradient id="background" x1="0" y1="0" x2="1" y2="1">
|
||||
<stop offset="0" stop-color="#241536"/>
|
||||
<stop offset="1" stop-color="#081221"/>
|
||||
</linearGradient>
|
||||
<marker id="arrowMint" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto">
|
||||
<path d="M0 0 L10 5 L0 10 z" fill="#4cdbbd"/>
|
||||
</marker>
|
||||
<marker id="arrowRose" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto">
|
||||
<path d="M0 0 L10 5 L0 10 z" fill="#ff87b3"/>
|
||||
</marker>
|
||||
<style>
|
||||
.kicker { font: 700 16px Arial, sans-serif; letter-spacing: 2px; fill: #ff9cc1; }
|
||||
.heading { font: 700 35px Arial, sans-serif; fill: #fff5fa; }
|
||||
.section { font: 700 26px Arial, sans-serif; fill: #fdf5ff; }
|
||||
.code { font: 19px Menlo, Consolas, monospace; fill: #dceaff; }
|
||||
.small { font: 20px Arial, sans-serif; fill: #e1d9ed; }
|
||||
.good { font: 700 20px Arial, sans-serif; fill: #082019; }
|
||||
.warn { font: 700 20px Arial, sans-serif; fill: #30101d; }
|
||||
</style>
|
||||
</defs>
|
||||
<rect width="720" height="1080" fill="url(#background)"/>
|
||||
<text x="44" y="58" class="kicker">FIELD DIAGNOSTIC · MODULE IDENTITY</text>
|
||||
<text x="44" y="106" class="heading">Сравниваем URL, а не считаем теги</text>
|
||||
|
||||
<rect x="44" y="148" width="632" height="326" rx="22" fill="#173f45" stroke="#69e0c5" stroke-width="2"/>
|
||||
<text x="76" y="194" class="section">Один разрешённый URL</text>
|
||||
<rect x="76" y="226" width="222" height="66" rx="12" fill="#244a56"/>
|
||||
<text x="98" y="267" class="code">catalog/main.js</text>
|
||||
<rect x="76" y="316" width="222" height="66" rx="12" fill="#244a56"/>
|
||||
<text x="98" y="357" class="code">admin/main.js</text>
|
||||
<path d="M298 259 H410" stroke="#4cdbbd" stroke-width="5" marker-end="url(#arrowMint)"/>
|
||||
<path d="M298 349 H410" stroke="#4cdbbd" stroke-width="5" marker-end="url(#arrowMint)"/>
|
||||
<rect x="426" y="262" width="214" height="98" rx="14" fill="#1a6558" stroke="#69e0c5" stroke-width="2"/>
|
||||
<text x="450" y="301" class="code">/assets/init.js</text>
|
||||
<text x="450" y="333" class="small">одна identity</text>
|
||||
<rect x="192" y="404" width="336" height="46" rx="23" fill="#76e4c9"/>
|
||||
<text x="286" y="434" class="good">URL = 1</text>
|
||||
|
||||
<rect x="44" y="516" width="632" height="350" rx="22" fill="#4d2c42" stroke="#ff9cc1" stroke-width="2"/>
|
||||
<text x="76" y="562" class="section">Разные разрешённые URL</text>
|
||||
<rect x="76" y="594" width="222" height="66" rx="12" fill="#59334a"/>
|
||||
<text x="98" y="635" class="code">catalog/main.js</text>
|
||||
<path d="M298 627 H410" stroke="#ff87b3" stroke-width="5" marker-end="url(#arrowRose)"/>
|
||||
<rect x="426" y="584" width="214" height="86" rx="14" fill="#743653" stroke="#ff9cc1" stroke-width="2"/>
|
||||
<text x="450" y="635" class="code">/assets/init.js</text>
|
||||
<rect x="76" y="704" width="222" height="66" rx="12" fill="#59334a"/>
|
||||
<text x="98" y="745" class="code">admin/main.js</text>
|
||||
<path d="M298 737 H410" stroke="#ff87b3" stroke-width="5" marker-end="url(#arrowRose)"/>
|
||||
<rect x="426" y="694" width="214" height="86" rx="14" fill="#743653" stroke="#ff9cc1" stroke-width="2"/>
|
||||
<text x="446" y="745" class="code">/assets/init.js?demo=2</text>
|
||||
<rect x="192" y="802" width="336" height="46" rx="23" fill="#ff9abf"/>
|
||||
<text x="286" y="832" class="warn">URL = 2</text>
|
||||
|
||||
<rect x="44" y="910" width="632" height="122" rx="18" fill="#131d32" stroke="#5f6f97" stroke-width="2"/>
|
||||
<text x="76" y="948" class="small">Проверка: import.meta.url → Initiator</text>
|
||||
<text x="76" y="978" class="small">→ status / MIME → entry-владелец</text>
|
||||
<text x="76" y="1008" class="small">→ один bootstrap</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.2 KiB |
@@ -0,0 +1,62 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="720" height="1040" viewBox="0 0 720 1040" role="img" aria-labelledby="title desc">
|
||||
<title id="title">Нативный граф ES-модулей в браузере</title>
|
||||
<desc id="desc">Вертикальная схема: HTML подключает app.js как модуль, app.js импортирует message.js, после готовности графа app.js обновляет output. Внизу перечислены четыре точки проверки.</desc>
|
||||
<defs>
|
||||
<linearGradient id="surface" x1="0" y1="0" x2="1" y2="1">
|
||||
<stop offset="0" stop-color="#10243c"/>
|
||||
<stop offset="1" stop-color="#07111e"/>
|
||||
</linearGradient>
|
||||
<marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto">
|
||||
<path d="M 0 0 L 10 5 L 0 10 z" fill="#66a9ff"/>
|
||||
</marker>
|
||||
<style>
|
||||
.kicker { font: 700 16px Arial, sans-serif; letter-spacing: 2px; fill: #7fe8cf; }
|
||||
.heading { font: 700 36px Arial, sans-serif; fill: #f4f8ff; }
|
||||
.label { font: 700 27px Arial, sans-serif; fill: #eef7ff; }
|
||||
.code { font: 20px Menlo, Consolas, monospace; fill: #c9ddff; }
|
||||
.small { font: 20px Arial, sans-serif; fill: #d2e0f1; }
|
||||
.step { font: 700 17px Arial, sans-serif; fill: #06111f; }
|
||||
</style>
|
||||
</defs>
|
||||
<rect width="720" height="1040" fill="url(#surface)"/>
|
||||
<text x="44" y="58" class="kicker">ES MODULES · 2019</text>
|
||||
<text x="44" y="106" class="heading">Нативный запуск: граф модулей</text>
|
||||
|
||||
<rect x="44" y="146" width="632" height="132" rx="18" fill="#183451" stroke="#4b7198" stroke-width="2"/>
|
||||
<circle cx="632" cy="180" r="20" fill="#49d4b2"/>
|
||||
<text x="626" y="186" class="step">1</text>
|
||||
<text x="76" y="190" class="label">index.html</text>
|
||||
<text x="76" y="226" class="code"><script type="module"</text>
|
||||
<text x="76" y="252" class="code">src="./assets/app.js"></text>
|
||||
|
||||
<path d="M360 278 V334" stroke="#66a9ff" stroke-width="5" marker-end="url(#arrow)"/>
|
||||
<text x="388" y="315" class="small">entry URL</text>
|
||||
|
||||
<rect x="44" y="350" width="632" height="132" rx="18" fill="#1b3c59" stroke="#66a9ff" stroke-width="2"/>
|
||||
<circle cx="632" cy="384" r="20" fill="#66a9ff"/>
|
||||
<text x="626" y="390" class="step">2</text>
|
||||
<text x="76" y="394" class="label">assets/app.js</text>
|
||||
<text x="76" y="430" class="code">import { message }</text>
|
||||
<text x="76" y="456" class="code">from "./message.js"</text>
|
||||
|
||||
<path d="M360 482 V538" stroke="#49d4b2" stroke-width="5" marker-end="url(#arrow)"/>
|
||||
<text x="388" y="519" class="small">relative URL</text>
|
||||
|
||||
<rect x="44" y="554" width="632" height="132" rx="18" fill="#24405a" stroke="#49d4b2" stroke-width="2"/>
|
||||
<circle cx="632" cy="588" r="20" fill="#7fe8cf"/>
|
||||
<text x="626" y="594" class="step">3</text>
|
||||
<text x="76" y="598" class="label">assets/message.js</text>
|
||||
<text x="76" y="634" class="code">export function message() { ... }</text>
|
||||
|
||||
<path d="M360 686 V742" stroke="#7fe8cf" stroke-width="5" marker-end="url(#arrow)"/>
|
||||
<text x="388" y="723" class="small">граф готов</text>
|
||||
|
||||
<rect x="44" y="758" width="632" height="94" rx="18" fill="#1d514e" stroke="#7fe8cf" stroke-width="2"/>
|
||||
<text x="76" y="797" class="label">output#status</text>
|
||||
<text x="76" y="828" class="code">модуль app.js получен</text>
|
||||
|
||||
<rect x="44" y="900" width="632" height="92" rx="16" fill="#0b1b2d" stroke="#345471"/>
|
||||
<text x="76" y="938" class="small">Проверка: URL entry → URL import</text>
|
||||
<text x="76" y="968" class="small">→ Content-Type / CORS → DOM-результат</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.6 KiB |
@@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="720" height="1030" viewBox="0 0 720 1030" role="img" aria-labelledby="title desc">
|
||||
<title id="title">Граница нативного разрешения ES-модуля и Webpack</title>
|
||||
<desc id="desc">Верхняя панель показывает: браузер превращает относительный import из main.js в запрос config.js. Нижняя панель показывает: Webpack заранее разрешает имя пакета, строит graph и выпускает asset. У import общий синтаксис, но разные этапы.</desc>
|
||||
<defs>
|
||||
<linearGradient id="background" x1="0" y1="0" x2="1" y2="1">
|
||||
<stop offset="0" stop-color="#111b34"/>
|
||||
<stop offset="1" stop-color="#07101f"/>
|
||||
</linearGradient>
|
||||
<marker id="blueArrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto">
|
||||
<path d="M0 0 L10 5 L0 10 z" fill="#79a9ff"/>
|
||||
</marker>
|
||||
<marker id="mintArrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto">
|
||||
<path d="M0 0 L10 5 L0 10 z" fill="#4cdbbd"/>
|
||||
</marker>
|
||||
<style>
|
||||
.kicker { font: 700 16px Arial, sans-serif; letter-spacing: 2px; fill: #91b9ff; }
|
||||
.heading { font: 700 35px Arial, sans-serif; fill: #f4f7ff; }
|
||||
.panel { font: 700 28px Arial, sans-serif; fill: #f4f7ff; }
|
||||
.label { font: 700 24px Arial, sans-serif; fill: #edf4ff; }
|
||||
.code { font: 19px Menlo, Consolas, monospace; fill: #d0e1ff; }
|
||||
.small { font: 20px Arial, sans-serif; fill: #d2dced; }
|
||||
.badge { font: 700 20px Arial, sans-serif; fill: #07111e; }
|
||||
</style>
|
||||
</defs>
|
||||
<rect width="720" height="1030" fill="url(#background)"/>
|
||||
<text x="44" y="58" class="kicker">ES MODULES · RESOLUTION BOUNDARY</text>
|
||||
<text x="44" y="106" class="heading">Одинаковый import, разные этапы</text>
|
||||
|
||||
<rect x="44" y="146" width="632" height="350" rx="22" fill="#142f4e" stroke="#6f9fe6" stroke-width="2"/>
|
||||
<text x="76" y="192" class="panel">Нативный браузер</text>
|
||||
<rect x="76" y="226" width="244" height="94" rx="14" fill="#1d466d"/>
|
||||
<text x="100" y="263" class="label">main.js</text>
|
||||
<text x="100" y="293" class="code">"./config.js"</text>
|
||||
<path d="M320 273 H430" stroke="#79a9ff" stroke-width="5" marker-end="url(#blueArrow)"/>
|
||||
<text x="332" y="247" class="small">URL</text>
|
||||
<rect x="446" y="226" width="194" height="94" rx="14" fill="#205a72"/>
|
||||
<text x="472" y="263" class="label">GET</text>
|
||||
<text x="472" y="293" class="code">config.js</text>
|
||||
<path d="M542 320 V362 H198" stroke="#79a9ff" stroke-width="5" fill="none" marker-end="url(#blueArrow)"/>
|
||||
<rect x="76" y="384" width="564" height="76" rx="14" fill="#0c2038"/>
|
||||
<text x="100" y="416" class="small">Проверяем: import → Request URL</text>
|
||||
<text x="100" y="445" class="small">→ HTTP-ответ. Нет aliases и .js-подбора.</text>
|
||||
|
||||
<rect x="44" y="538" width="632" height="350" rx="22" fill="#173b3b" stroke="#5ed5bc" stroke-width="2"/>
|
||||
<text x="76" y="584" class="panel">Webpack до браузера</text>
|
||||
<rect x="76" y="618" width="224" height="94" rx="14" fill="#1d5a55"/>
|
||||
<text x="100" y="655" class="label">source import</text>
|
||||
<text x="100" y="685" class="code">"date-kit"</text>
|
||||
<path d="M300 665 H410" stroke="#4cdbbd" stroke-width="5" marker-end="url(#mintArrow)"/>
|
||||
<rect x="426" y="618" width="214" height="94" rx="14" fill="#1d7269"/>
|
||||
<text x="450" y="655" class="label">resolve</text>
|
||||
<text x="450" y="685" class="code">graph</text>
|
||||
<path d="M533 712 V754 H198" stroke="#4cdbbd" stroke-width="5" fill="none" marker-end="url(#mintArrow)"/>
|
||||
<rect x="76" y="776" width="564" height="76" rx="14" fill="#0d2827"/>
|
||||
<text x="100" y="808" class="small">Проверяем: config → resolved module</text>
|
||||
<text x="100" y="837" class="small">→ emitted asset. Aliases живут здесь.</text>
|
||||
|
||||
<rect x="126" y="930" width="468" height="56" rx="28" fill="#f2c66c"/>
|
||||
<text x="203" y="966" class="badge">import — общий синтаксис</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.1 KiB |
@@ -0,0 +1,35 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 720 1220" role="img" aria-labelledby="title desc">
|
||||
<title id="title">Длинная синхронная задача занимает главный поток</title>
|
||||
<desc id="desc">Вертикальная шкала показывает длинный синхронный обработчик, задержанный input, а затем короткие порции работы, между которыми event loop может выбрать input и paint.</desc>
|
||||
<rect width="720" height="1220" rx="32" fill="#0f172a"/>
|
||||
<text x="56" y="82" fill="#f8fafc" font-family="Arial, sans-serif" font-size="40" font-weight="700">Почему async-экран</text>
|
||||
<text x="56" y="124" fill="#f8fafc" font-family="Arial, sans-serif" font-size="40" font-weight="700">всё равно зависает</text>
|
||||
<text x="56" y="172" fill="#94a3b8" font-family="Arial, sans-serif" font-size="24">Promise не выносит вычисление с главного потока.</text>
|
||||
<text x="56" y="204" fill="#94a3b8" font-family="Arial, sans-serif" font-size="24">Пока стек занят, input и render ждут.</text>
|
||||
<g font-family="Arial, sans-serif">
|
||||
<text x="56" y="274" fill="#cbd5e1" font-size="28" font-weight="700">До: один обработчик</text>
|
||||
<line x1="56" y1="300" x2="664" y2="300" stroke="#475569" stroke-width="4"/>
|
||||
<rect x="56" y="330" width="608" height="122" rx="16" fill="#dc2626"/>
|
||||
<text x="360" y="382" fill="#fff" font-size="29" font-weight="700" text-anchor="middle">sync import + parse + render</text>
|
||||
<text x="360" y="420" fill="#fee2e2" font-size="22" text-anchor="middle">main thread занят до return</text>
|
||||
<rect x="56" y="478" width="608" height="84" rx="16" fill="#64748b"/>
|
||||
<text x="360" y="530" fill="#fff" font-size="25" text-anchor="middle">input уже ждёт, но обработчик не начнётся</text>
|
||||
<text x="56" y="650" fill="#cbd5e1" font-size="28" font-weight="700">После: короткие порции</text>
|
||||
<line x1="56" y1="676" x2="664" y2="676" stroke="#475569" stroke-width="4"/>
|
||||
<rect x="56" y="708" width="282" height="90" rx="15" fill="#2563eb"/>
|
||||
<rect x="382" y="708" width="282" height="90" rx="15" fill="#2563eb"/>
|
||||
<text x="197" y="764" fill="#fff" font-size="26" text-anchor="middle">slice 1</text>
|
||||
<text x="523" y="764" fill="#fff" font-size="26" text-anchor="middle">slice 2</text>
|
||||
<rect x="56" y="824" width="282" height="90" rx="15" fill="#2563eb"/>
|
||||
<rect x="382" y="824" width="282" height="90" rx="15" fill="#2563eb"/>
|
||||
<text x="197" y="880" fill="#fff" font-size="26" text-anchor="middle">slice 3</text>
|
||||
<text x="523" y="880" fill="#fff" font-size="26" text-anchor="middle">slice 4</text>
|
||||
<rect x="56" y="942" width="282" height="90" rx="15" fill="#10b981"/>
|
||||
<rect x="382" y="942" width="282" height="90" rx="15" fill="#eab308"/>
|
||||
<text x="197" y="998" fill="#052e16" font-size="26" text-anchor="middle">input</text>
|
||||
<text x="523" y="998" fill="#422006" font-size="26" text-anchor="middle">paint</text>
|
||||
</g>
|
||||
<rect x="56" y="1074" width="608" height="94" rx="16" fill="#1e293b"/>
|
||||
<text x="88" y="1114" fill="#e2e8f0" font-family="Arial, sans-serif" font-size="24">Порции отдают управление event loop.</text>
|
||||
<text x="88" y="1150" fill="#cbd5e1" font-family="Arial, sans-serif" font-size="21">Проверяем это профилем, а не именем функции.</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.5 KiB |
@@ -0,0 +1,34 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 720 1220" role="img" aria-labelledby="title desc">
|
||||
<title id="title">Очередность синхронного кода, microtask и timer-задачи</title>
|
||||
<desc id="desc">Вертикальная схема показывает: синхронный код завершает текущий стек, затем выполняется microtask Promise, после чего event loop может выбрать timer-задачу.</desc>
|
||||
<rect width="720" height="1220" rx="32" fill="#0f172a"/>
|
||||
<text x="56" y="82" fill="#f8fafc" font-family="Arial, sans-serif" font-size="40" font-weight="700">Порядок одного тика</text>
|
||||
<text x="56" y="124" fill="#f8fafc" font-family="Arial, sans-serif" font-size="40" font-weight="700">не угадываем, записываем</text>
|
||||
<text x="56" y="172" fill="#94a3b8" font-family="Arial, sans-serif" font-size="25">Сначала стек, затем microtask checkpoint,</text>
|
||||
<text x="56" y="206" fill="#94a3b8" font-family="Arial, sans-serif" font-size="25">после этого — следующая доступная task.</text>
|
||||
<g font-family="Arial, sans-serif">
|
||||
<rect x="56" y="268" width="608" height="174" rx="22" fill="#2563eb"/>
|
||||
<circle cx="116" cy="326" r="34" fill="#dbeafe"/>
|
||||
<text x="116" y="335" fill="#1e3a8a" font-size="25" font-weight="700" text-anchor="middle">1</text>
|
||||
<text x="174" y="330" fill="#fff" font-size="31" font-weight="700">Текущий стек</text>
|
||||
<text x="174" y="370" fill="#dbeafe" font-size="25">sync: A, затем D</text>
|
||||
<text x="174" y="406" fill="#dbeafe" font-size="22">Выполнить функцию до return.</text>
|
||||
<path d="M360 462v58l-23-25h46z" fill="#64748b"/>
|
||||
<rect x="56" y="548" width="608" height="174" rx="22" fill="#7c3aed"/>
|
||||
<circle cx="116" cy="606" r="34" fill="#ede9fe"/>
|
||||
<text x="116" y="615" fill="#4c1d95" font-size="25" font-weight="700" text-anchor="middle">2</text>
|
||||
<text x="174" y="610" fill="#fff" font-size="31" font-weight="700">Microtask checkpoint</text>
|
||||
<text x="174" y="650" fill="#ede9fe" font-size="25">Promise: B</text>
|
||||
<text x="174" y="686" fill="#ede9fe" font-size="22">Очистить накопленную очередь.</text>
|
||||
<path d="M360 742v58l-23-25h46z" fill="#64748b"/>
|
||||
<rect x="56" y="828" width="608" height="174" rx="22" fill="#0891b2"/>
|
||||
<circle cx="116" cy="886" r="34" fill="#cffafe"/>
|
||||
<text x="116" y="895" fill="#155e75" font-size="25" font-weight="700" text-anchor="middle">3</text>
|
||||
<text x="174" y="890" fill="#fff" font-size="31" font-weight="700">Будущая task</text>
|
||||
<text x="174" y="930" fill="#cffafe" font-size="25">timer: C</text>
|
||||
<text x="174" y="966" fill="#cffafe" font-size="22">Event loop выбирает доступную работу.</text>
|
||||
</g>
|
||||
<rect x="56" y="1064" width="608" height="104" rx="16" fill="#1e293b"/>
|
||||
<text x="88" y="1112" fill="#e2e8f0" font-family="Arial, sans-serif" font-size="25">Порядок опыта: A → D → B → C.</text>
|
||||
<text x="88" y="1148" fill="#cbd5e1" font-family="Arial, sans-serif" font-size="21">Timer не обязан запускаться сразу после 0 ms.</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.2 KiB |
@@ -0,0 +1,34 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 720 1220" role="img" aria-labelledby="title desc">
|
||||
<title id="title">Маршрут диагностики неожиданного порядка async колбэков</title>
|
||||
<desc id="desc">Вертикальная схема ведёт от отметок времени и номера запуска через разделение sync, microtask и task к проверке длинной работы в performance trace.</desc>
|
||||
<rect width="720" height="1220" rx="32" fill="#0f172a"/>
|
||||
<text x="56" y="82" fill="#f8fafc" font-family="Arial, sans-serif" font-size="40" font-weight="700">Маршрут разбора:</text>
|
||||
<text x="56" y="124" fill="#f8fafc" font-family="Arial, sans-serif" font-size="40" font-weight="700">от лога к причине</text>
|
||||
<text x="56" y="172" fill="#94a3b8" font-family="Arial, sans-serif" font-size="24">Не называем очередь сломанной, пока не записали</text>
|
||||
<text x="56" y="204" fill="#94a3b8" font-family="Arial, sans-serif" font-size="24">источник callback и sync-границу.</text>
|
||||
<g font-family="Arial, sans-serif">
|
||||
<rect x="56" y="274" width="608" height="184" rx="22" fill="#1d4ed8"/>
|
||||
<circle cx="116" cy="332" r="34" fill="#dbeafe"/>
|
||||
<text x="116" y="341" fill="#1e3a8a" font-size="25" font-weight="700" text-anchor="middle">1</text>
|
||||
<text x="174" y="336" fill="#fff" font-size="31" font-weight="700">Записать лог</text>
|
||||
<text x="174" y="376" fill="#dbeafe" font-size="24">label, runId, performance.now()</text>
|
||||
<text x="174" y="412" fill="#dbeafe" font-size="21">и источник каждого callback.</text>
|
||||
<path d="M360 478v58l-23-25h46z" fill="#64748b"/>
|
||||
<rect x="56" y="564" width="608" height="184" rx="22" fill="#7c3aed"/>
|
||||
<circle cx="116" cy="622" r="34" fill="#ede9fe"/>
|
||||
<text x="116" y="631" fill="#4c1d95" font-size="25" font-weight="700" text-anchor="middle">2</text>
|
||||
<text x="174" y="626" fill="#fff" font-size="31" font-weight="700">Классифицировать</text>
|
||||
<text x="174" y="666" fill="#ede9fe" font-size="24">sync / microtask / task</text>
|
||||
<text x="174" y="702" fill="#ede9fe" font-size="21">или длинную работу main thread.</text>
|
||||
<path d="M360 768v58l-23-25h46z" fill="#64748b"/>
|
||||
<rect x="56" y="854" width="608" height="184" rx="22" fill="#0f766e"/>
|
||||
<circle cx="116" cy="912" r="34" fill="#ccfbf1"/>
|
||||
<text x="116" y="921" fill="#115e59" font-size="25" font-weight="700" text-anchor="middle">3</text>
|
||||
<text x="174" y="916" fill="#fff" font-size="31" font-weight="700">Выбрать действие</text>
|
||||
<text x="174" y="956" fill="#ccfbf1" font-size="24">явная зависимость, отмена</text>
|
||||
<text x="174" y="992" fill="#ccfbf1" font-size="21">или работа с CPU/DOM-границей.</text>
|
||||
</g>
|
||||
<rect x="56" y="1074" width="608" height="94" rx="16" fill="#1e293b"/>
|
||||
<text x="88" y="1114" fill="#e2e8f0" font-family="Arial, sans-serif" font-size="24">Порядок и задержка повторяемы.</text>
|
||||
<text x="88" y="1150" fill="#cbd5e1" font-family="Arial, sans-serif" font-size="21">Один удачный запуск не закрывает проверку.</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.3 KiB |
@@ -0,0 +1,56 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 720 820" role="img" aria-labelledby="title desc">
|
||||
<title id="title">Контракт валидации формы</title>
|
||||
<desc id="desc">Вертикальная схема: HTML проверяет форму ввода, клиент хранит версию и привязывает ошибки к полю, сервер проверяет данные и возвращает ключ поля. Старый ответ не имеет права изменить новое значение.</desc>
|
||||
<defs>
|
||||
<linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
|
||||
<stop offset="0" stop-color="#091c2d"/>
|
||||
<stop offset="1" stop-color="#12344c"/>
|
||||
</linearGradient>
|
||||
<filter id="shadow" x="-20%" y="-20%" width="140%" height="140%">
|
||||
<feDropShadow dx="0" dy="8" stdDeviation="10" flood-color="#03111e" flood-opacity=".32"/>
|
||||
</filter>
|
||||
<marker id="arrow" markerWidth="10" markerHeight="10" refX="8" refY="5" orient="auto">
|
||||
<path d="M0 0L10 5L0 10z" fill="#8de4da"/>
|
||||
</marker>
|
||||
<marker id="coralArrow" markerWidth="10" markerHeight="10" refX="8" refY="5" orient="auto">
|
||||
<path d="M0 0L10 5L0 10z" fill="#ff9a8b"/>
|
||||
</marker>
|
||||
</defs>
|
||||
<rect width="720" height="820" rx="34" fill="url(#bg)"/>
|
||||
<text x="56" y="68" fill="#ffffff" font-family="Arial, sans-serif" font-size="30" font-weight="700">Форма: один контракт, три владельца</text>
|
||||
<text x="56" y="102" fill="#bdd4e5" font-family="Arial, sans-serif" font-size="18">Симптом: браузер считает поле нормальным, API отказывает.</text>
|
||||
|
||||
<g filter="url(#shadow)">
|
||||
<rect x="56" y="146" width="608" height="144" rx="22" fill="#e8f8f3"/>
|
||||
<rect x="56" y="146" width="14" height="144" rx="7" fill="#36b7a1"/>
|
||||
<text x="96" y="190" fill="#103543" font-family="Arial, sans-serif" font-size="24" font-weight="700">1. HTML-контрол</text>
|
||||
<text x="96" y="224" fill="#294f5b" font-family="Arial, sans-serif" font-size="19">required · type=email · pattern</text>
|
||||
<text x="96" y="256" fill="#294f5b" font-family="Arial, sans-serif" font-size="19">Даёт ранний сигнал, но не знает базу.</text>
|
||||
</g>
|
||||
<path d="M360 290V340" stroke="#8de4da" stroke-width="7" stroke-linecap="round" marker-end="url(#arrow)"/>
|
||||
<text x="390" y="325" fill="#8de4da" font-family="Arial, sans-serif" font-size="16">локально корректно</text>
|
||||
|
||||
<g filter="url(#shadow)">
|
||||
<rect x="56" y="350" width="608" height="176" rx="22" fill="#eaf0ff"/>
|
||||
<rect x="56" y="350" width="14" height="176" rx="7" fill="#6579df"/>
|
||||
<text x="96" y="394" fill="#1d326b" font-family="Arial, sans-serif" font-size="24" font-weight="700">2. Клиентское состояние</text>
|
||||
<text x="96" y="428" fill="#32487c" font-family="Arial, sans-serif" font-size="19">value + requestId + phase + fieldError</text>
|
||||
<text x="96" y="460" fill="#32487c" font-family="Arial, sans-serif" font-size="19">Сравнивает версию до render.</text>
|
||||
<rect x="436" y="412" width="184" height="70" rx="14" fill="#ffffff" stroke="#6579df" stroke-width="2"/>
|
||||
<text x="456" y="440" fill="#1d326b" font-family="Arial, sans-serif" font-size="17" font-weight="700">email-error</text>
|
||||
<text x="456" y="465" fill="#32487c" font-family="Arial, sans-serif" font-size="15">aria-invalid=true</text>
|
||||
</g>
|
||||
<path d="M360 526V576" stroke="#8de4da" stroke-width="7" stroke-linecap="round" marker-end="url(#arrow)"/>
|
||||
<text x="390" y="560" fill="#8de4da" font-family="Arial, sans-serif" font-size="16">проверка условия</text>
|
||||
|
||||
<g filter="url(#shadow)">
|
||||
<rect x="56" y="586" width="608" height="144" rx="22" fill="#fff3e7"/>
|
||||
<rect x="56" y="586" width="14" height="144" rx="7" fill="#f39a4b"/>
|
||||
<text x="96" y="630" fill="#6a3a16" font-family="Arial, sans-serif" font-size="24" font-weight="700">3. API и данные</text>
|
||||
<text x="96" y="664" fill="#80512a" font-family="Arial, sans-serif" font-size="19">Занятость, права, нормализация, сохранение.</text>
|
||||
<text x="96" y="696" fill="#80512a" font-family="Arial, sans-serif" font-size="19">Возвращает fields.email и код ошибки.</text>
|
||||
</g>
|
||||
|
||||
<path d="M82 752C82 786 638 786 638 752" fill="none" stroke="#ff9a8b" stroke-width="5" stroke-linecap="round" marker-end="url(#coralArrow)"/>
|
||||
<text x="181" y="794" fill="#ffb7ac" font-family="Arial, sans-serif" font-size="17" font-weight="700">старый requestId → не меняет новое поле</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.6 KiB |
@@ -0,0 +1,61 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 720 860" role="img" aria-labelledby="title desc">
|
||||
<title id="title">Поздний ответ не меняет новое поле</title>
|
||||
<desc id="desc">Временная диаграмма проверки логина: пользователь сначала вводит ivan и запускает медленный запрос с requestId 1, затем ivanka с requestId 2. Быстрый новый ответ применён, поздний старый ответ отклонён как устаревший.</desc>
|
||||
<defs>
|
||||
<linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
|
||||
<stop offset="0" stop-color="#162332"/>
|
||||
<stop offset="1" stop-color="#1d4658"/>
|
||||
</linearGradient>
|
||||
<marker id="arrow" markerWidth="10" markerHeight="10" refX="8" refY="5" orient="auto">
|
||||
<path d="M0 0L10 5L0 10z" fill="#98e0e8"/>
|
||||
</marker>
|
||||
<marker id="danger" markerWidth="10" markerHeight="10" refX="8" refY="5" orient="auto">
|
||||
<path d="M0 0L10 5L0 10z" fill="#ff9d8d"/>
|
||||
</marker>
|
||||
</defs>
|
||||
<rect width="720" height="860" rx="34" fill="url(#bg)"/>
|
||||
<text x="54" y="66" fill="#ffffff" font-family="Arial, sans-serif" font-size="30" font-weight="700">Два ответа, одно актуальное поле</text>
|
||||
<text x="54" y="100" fill="#c6dce9" font-family="Arial, sans-serif" font-size="18">Нельзя доверять времени ответа: сравниваем requestId.</text>
|
||||
|
||||
<g font-family="Arial, sans-serif">
|
||||
<text x="70" y="156" fill="#b9d5e4" font-size="18" font-weight="700">Пользователь</text>
|
||||
<text x="294" y="156" fill="#b9d5e4" font-size="18" font-weight="700">Форма</text>
|
||||
<text x="520" y="156" fill="#b9d5e4" font-size="18" font-weight="700">Проверка API</text>
|
||||
<path d="M150 174H650" stroke="#7ba2b6" stroke-width="2" stroke-dasharray="8 8"/>
|
||||
<path d="M150 174V746" stroke="#7ba2b6" stroke-width="2" stroke-dasharray="8 8"/>
|
||||
<path d="M370 174V746" stroke="#7ba2b6" stroke-width="2" stroke-dasharray="8 8"/>
|
||||
<path d="M604 174V746" stroke="#7ba2b6" stroke-width="2" stroke-dasharray="8 8"/>
|
||||
|
||||
<text x="68" y="230" fill="#ffffff" font-size="20">1. Ввод: ivan</text>
|
||||
<path d="M178 238H348" stroke="#98e0e8" stroke-width="6" marker-end="url(#arrow)"/>
|
||||
<rect x="238" y="258" width="236" height="74" rx="16" fill="#d9f5f4"/>
|
||||
<text x="260" y="289" fill="#15545a" font-size="18" font-weight="700">requestId = 1</text>
|
||||
<text x="260" y="314" fill="#2e7478" font-size="16">checking: ivan</text>
|
||||
<path d="M382 296H582" stroke="#98e0e8" stroke-width="6" marker-end="url(#arrow)"/>
|
||||
<text x="430" y="282" fill="#c6dce9" font-size="15">медленный ответ</text>
|
||||
|
||||
<text x="58" y="394" fill="#ffffff" font-size="20">2. Ввод: ivanka</text>
|
||||
<path d="M188 402H348" stroke="#98e0e8" stroke-width="6" marker-end="url(#arrow)"/>
|
||||
<rect x="238" y="422" width="236" height="74" rx="16" fill="#d9f5f4"/>
|
||||
<text x="260" y="453" fill="#15545a" font-size="18" font-weight="700">requestId = 2</text>
|
||||
<text x="260" y="478" fill="#2e7478" font-size="16">checking: ivanka</text>
|
||||
<path d="M382 460H582" stroke="#98e0e8" stroke-width="6" marker-end="url(#arrow)"/>
|
||||
<text x="432" y="446" fill="#c6dce9" font-size="15">быстрый ответ</text>
|
||||
|
||||
<path d="M594 506H394" stroke="#89e5b1" stroke-width="7" marker-end="url(#arrow)"/>
|
||||
<rect x="212" y="530" width="260" height="78" rx="16" fill="#d4f4df"/>
|
||||
<text x="236" y="562" fill="#15553a" font-size="19" font-weight="700">apply: requestId 2</text>
|
||||
<text x="236" y="588" fill="#2e7750" font-size="16">ivanka · valid · error пуст</text>
|
||||
<text x="482" y="540" fill="#9ee6b9" font-size="16">available</text>
|
||||
|
||||
<path d="M594 646H394" stroke="#ff9d8d" stroke-width="7" marker-end="url(#danger)"/>
|
||||
<path d="M358 620L426 688" stroke="#ff9d8d" stroke-width="8" stroke-linecap="round"/>
|
||||
<path d="M426 620L358 688" stroke="#ff9d8d" stroke-width="8" stroke-linecap="round"/>
|
||||
<text x="482" y="634" fill="#ffc2b8" font-size="16">occupied, но поздно</text>
|
||||
<rect x="212" y="704" width="316" height="72" rx="16" fill="#563543" stroke="#ff9d8d" stroke-width="2"/>
|
||||
<text x="236" y="735" fill="#ffd8d0" font-size="19" font-weight="700">ignore: stale-response</text>
|
||||
<text x="236" y="760" fill="#ffc2b8" font-size="16">1 !== current requestId 2</text>
|
||||
</g>
|
||||
<rect x="54" y="804" width="612" height="34" rx="17" fill="#235e6c"/>
|
||||
<text x="94" y="827" fill="#e7fbff" font-family="Arial, sans-serif" font-size="16" font-weight="700">Новый input очищает старую ошибку раньше следующего render.</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.7 KiB |
@@ -0,0 +1,61 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 720 900" role="img" aria-labelledby="title desc">
|
||||
<title id="title">Конечный автомат проверки одного поля</title>
|
||||
<desc id="desc">Схема показывает переходы поля: editing, client-invalid, checking, ready и remote-invalid. Каждый новый input увеличивает версию и очищает старый удалённый результат. Устаревший ответ обрывается до изменения состояния.</desc>
|
||||
<defs>
|
||||
<linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
|
||||
<stop offset="0" stop-color="#17142e"/>
|
||||
<stop offset="1" stop-color="#342056"/>
|
||||
</linearGradient>
|
||||
<marker id="arrow" markerWidth="10" markerHeight="10" refX="8" refY="5" orient="auto">
|
||||
<path d="M0 0L10 5L0 10z" fill="#c7b5ff"/>
|
||||
</marker>
|
||||
<marker id="mutedArrow" markerWidth="10" markerHeight="10" refX="8" refY="5" orient="auto">
|
||||
<path d="M0 0L10 5L0 10z" fill="#9aa4bb"/>
|
||||
</marker>
|
||||
</defs>
|
||||
<rect width="720" height="900" rx="34" fill="url(#bg)"/>
|
||||
<text x="54" y="66" fill="#ffffff" font-family="Arial, sans-serif" font-size="30" font-weight="700">Поле как небольшой автомат</text>
|
||||
<text x="54" y="100" fill="#d7cff5" font-family="Arial, sans-serif" font-size="18">Версия — условие, по которому ответ получает право изменить UI.</text>
|
||||
|
||||
<g font-family="Arial, sans-serif">
|
||||
<rect x="216" y="144" width="288" height="92" rx="46" fill="#dcd4ff"/>
|
||||
<text x="278" y="181" fill="#30205f" font-size="25" font-weight="700">editing</text>
|
||||
<text x="248" y="211" fill="#4b3978" font-size="17">value изменён · version + 1</text>
|
||||
|
||||
<path d="M216 190H132V310" fill="none" stroke="#c7b5ff" stroke-width="6" marker-end="url(#arrow)"/>
|
||||
<text x="52" y="256" fill="#d7cff5" font-size="16">локальная ошибка</text>
|
||||
<rect x="52" y="320" width="244" height="96" rx="20" fill="#ffccd2"/>
|
||||
<text x="76" y="359" fill="#6f2634" font-size="23" font-weight="700">client-invalid</text>
|
||||
<text x="76" y="389" fill="#8b4050" font-size="16">сеть не запускаем</text>
|
||||
|
||||
<path d="M504 190H588V310" fill="none" stroke="#c7b5ff" stroke-width="6" marker-end="url(#arrow)"/>
|
||||
<text x="522" y="256" fill="#d7cff5" font-size="16">локально корректно</text>
|
||||
<rect x="424" y="320" width="244" height="96" rx="20" fill="#c5eff0"/>
|
||||
<text x="478" y="359" fill="#174e56" font-size="23" font-weight="700">checking</text>
|
||||
<text x="456" y="389" fill="#2a6870" font-size="16">запомнить version</text>
|
||||
|
||||
<path d="M546 416V506H452" fill="none" stroke="#c7b5ff" stroke-width="6" marker-end="url(#arrow)"/>
|
||||
<text x="472" y="482" fill="#d7cff5" font-size="16">available</text>
|
||||
<rect x="226" y="518" width="244" height="96" rx="20" fill="#c9f1d9"/>
|
||||
<text x="310" y="557" fill="#145339" font-size="23" font-weight="700">ready</text>
|
||||
<text x="264" y="587" fill="#28704e" font-size="16">можно отправлять форму</text>
|
||||
|
||||
<path d="M546 416V676H452" fill="none" stroke="#c7b5ff" stroke-width="6" marker-end="url(#arrow)"/>
|
||||
<text x="556" y="580" fill="#d7cff5" font-size="16">occupied</text>
|
||||
<rect x="226" y="690" width="244" height="96" rx="20" fill="#ffd8bd"/>
|
||||
<text x="253" y="729" fill="#713a1a" font-size="22" font-weight="700">remote-invalid</text>
|
||||
<text x="250" y="759" fill="#8b5432" font-size="16">ошибка у этого поля</text>
|
||||
|
||||
<path d="M226 566C94 566 94 190 208 190" fill="none" stroke="#c7b5ff" stroke-width="5" stroke-dasharray="10 10" marker-end="url(#arrow)"/>
|
||||
<path d="M226 738C110 738 110 190 208 190" fill="none" stroke="#c7b5ff" stroke-width="5" stroke-dasharray="10 10" marker-end="url(#arrow)"/>
|
||||
<text x="58" y="464" fill="#d7cff5" font-size="16">любой input → очистить</text>
|
||||
<text x="58" y="486" fill="#d7cff5" font-size="16">старую remoteError</text>
|
||||
|
||||
<path d="M578 462L642 526" stroke="#9aa4bb" stroke-width="5" stroke-linecap="round"/>
|
||||
<path d="M642 462L578 526" stroke="#9aa4bb" stroke-width="5" stroke-linecap="round"/>
|
||||
<text x="510" y="556" fill="#b7bfd0" font-size="15">старая версия</text>
|
||||
<text x="510" y="577" fill="#b7bfd0" font-size="15">не делает render</text>
|
||||
</g>
|
||||
<rect x="54" y="830" width="612" height="38" rx="19" fill="#4c397b"/>
|
||||
<text x="90" y="856" fill="#f1edff" font-family="Arial, sans-serif" font-size="17" font-weight="700">Ответ применяем, только если checkedVersion === current.version</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.6 KiB |
@@ -0,0 +1,45 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 720 1120" role="img" aria-labelledby="title desc">
|
||||
<title id="title">Как HTTP-кэш выбирает вариант ответа</title>
|
||||
<desc id="desc">Схема показывает, что URL и поля из Vary образуют ключ варианта, затем кэш проверяет свежесть и при истечении срока валидирует ETag у origin.</desc>
|
||||
<rect width="720" height="1120" fill="#f8fafc"/>
|
||||
<rect x="42" y="34" width="636" height="108" rx="18" fill="#1e293b"/>
|
||||
<text x="360" y="78" text-anchor="middle" fill="#fff" font-size="28" font-family="Arial, sans-serif" font-weight="700">Ответ выбирается по ключу, а не по TTL</text>
|
||||
<text x="360" y="112" text-anchor="middle" fill="#cbd5e1" font-size="20" font-family="Arial, sans-serif">URL + входы, перечисленные в Vary</text>
|
||||
|
||||
<rect x="82" y="192" width="556" height="108" rx="16" fill="#e0f2fe" stroke="#0284c7" stroke-width="3"/>
|
||||
<text x="360" y="234" text-anchor="middle" fill="#0c4a6e" font-size="25" font-family="Arial, sans-serif" font-weight="700">GET /catalog</text>
|
||||
<text x="360" y="268" text-anchor="middle" fill="#0c4a6e" font-size="20" font-family="Arial, sans-serif">Accept-Language: ru</text>
|
||||
<path d="M360 300v48" stroke="#334155" stroke-width="5" marker-end="url(#arrow)"/>
|
||||
|
||||
<rect x="82" y="352" width="556" height="132" rx="16" fill="#fef3c7" stroke="#d97706" stroke-width="3"/>
|
||||
<text x="360" y="395" text-anchor="middle" fill="#78350f" font-size="25" font-family="Arial, sans-serif" font-weight="700">Ключ варианта</text>
|
||||
<text x="360" y="431" text-anchor="middle" fill="#78350f" font-size="20" font-family="Arial, sans-serif">URL + Accept-Language</text>
|
||||
<text x="360" y="459" text-anchor="middle" fill="#78350f" font-size="18" font-family="Arial, sans-serif">если origin отдал Vary: Accept-Language</text>
|
||||
<path d="M360 484v48" stroke="#334155" stroke-width="5" marker-end="url(#arrow)"/>
|
||||
|
||||
<rect x="110" y="536" width="500" height="110" rx="16" fill="#ede9fe" stroke="#7c3aed" stroke-width="3"/>
|
||||
<text x="360" y="578" text-anchor="middle" fill="#4c1d95" font-size="25" font-family="Arial, sans-serif" font-weight="700">Найдено представление ru</text>
|
||||
<text x="360" y="612" text-anchor="middle" fill="#4c1d95" font-size="19" font-family="Arial, sans-serif">Cache-Control задаёт его свежесть</text>
|
||||
<path d="M360 646v52" stroke="#334155" stroke-width="5" marker-end="url(#arrow)"/>
|
||||
|
||||
<rect x="80" y="702" width="254" height="116" rx="16" fill="#dcfce7" stroke="#16a34a" stroke-width="3"/>
|
||||
<text x="207" y="748" text-anchor="middle" fill="#14532d" font-size="24" font-family="Arial, sans-serif" font-weight="700">Свежий</text>
|
||||
<text x="207" y="781" text-anchor="middle" fill="#14532d" font-size="18" font-family="Arial, sans-serif">вернуть тело</text>
|
||||
<rect x="386" y="702" width="254" height="116" rx="16" fill="#fee2e2" stroke="#dc2626" stroke-width="3"/>
|
||||
<text x="513" y="748" text-anchor="middle" fill="#7f1d1d" font-size="24" font-family="Arial, sans-serif" font-weight="700">Устарел</text>
|
||||
<text x="513" y="781" text-anchor="middle" fill="#7f1d1d" font-size="18" font-family="Arial, sans-serif">проверить ETag</text>
|
||||
<path d="M513 818v52" stroke="#334155" stroke-width="5" marker-end="url(#arrow)"/>
|
||||
|
||||
<rect x="110" y="874" width="500" height="114" rx="16" fill="#e0f2fe" stroke="#0284c7" stroke-width="3"/>
|
||||
<text x="360" y="916" text-anchor="middle" fill="#0c4a6e" font-size="24" font-family="Arial, sans-serif" font-weight="700">If-None-Match → origin</text>
|
||||
<text x="360" y="951" text-anchor="middle" fill="#0c4a6e" font-size="19" font-family="Arial, sans-serif">304 подтверждает тело; 200 даёт новый вариант</text>
|
||||
|
||||
<rect x="110" y="1032" width="500" height="54" rx="14" fill="#fff7ed" stroke="#ea580c" stroke-width="3"/>
|
||||
<text x="360" y="1067" text-anchor="middle" fill="#7c2d12" font-size="19" font-family="Arial, sans-serif">Неполный ключ может вернуть свежий, но чужой язык</text>
|
||||
|
||||
<defs>
|
||||
<marker id="arrow" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse">
|
||||
<path d="M0 0L10 5L0 10z" fill="#334155"/>
|
||||
</marker>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.4 KiB |
@@ -0,0 +1,47 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 720 1160" role="img" aria-labelledby="title desc">
|
||||
<title id="title">Путь HTTP-ответа для HTML, asset и API</title>
|
||||
<desc id="desc">Вертикальная схема показывает, как браузер проверяет HTML с no-cache и ETag, получает новый URL версионированного JavaScript и отдельно применяет короткую свежесть к API.</desc>
|
||||
<rect width="720" height="1160" fill="#f8fafc"/>
|
||||
<rect x="44" y="34" width="632" height="110" rx="18" fill="#172554"/>
|
||||
<text x="360" y="78" text-anchor="middle" fill="#fff" font-size="28" font-family="Arial, sans-serif" font-weight="700">Один домен — три контракта ответа</text>
|
||||
<text x="360" y="112" text-anchor="middle" fill="#cbd5e1" font-size="20" font-family="Arial, sans-serif">Сначала тип ресурса, потом TTL</text>
|
||||
|
||||
<rect x="140" y="188" width="440" height="110" rx="16" fill="#e0f2fe" stroke="#0284c7" stroke-width="3"/>
|
||||
<text x="360" y="232" text-anchor="middle" fill="#0c4a6e" font-size="27" font-family="Arial, sans-serif" font-weight="700">HTML /catalog</text>
|
||||
<text x="360" y="267" text-anchor="middle" fill="#0c4a6e" font-size="21" font-family="Arial, sans-serif">no-cache + ETag</text>
|
||||
<path d="M360 298v52" stroke="#334155" stroke-width="5" marker-end="url(#arrow)"/>
|
||||
|
||||
<rect x="90" y="354" width="540" height="136" rx="16" fill="#fef3c7" stroke="#d97706" stroke-width="3"/>
|
||||
<text x="360" y="397" text-anchor="middle" fill="#78350f" font-size="26" font-family="Arial, sans-serif" font-weight="700">Кэш проверяет сохранённый HTML</text>
|
||||
<text x="360" y="431" text-anchor="middle" fill="#78350f" font-size="20" font-family="Arial, sans-serif">свежий — использует; устаревший —</text>
|
||||
<text x="360" y="460" text-anchor="middle" fill="#78350f" font-size="20" font-family="Arial, sans-serif">отправляет If-None-Match к origin</text>
|
||||
<path d="M360 490v52" stroke="#334155" stroke-width="5" marker-end="url(#arrow)"/>
|
||||
|
||||
<rect x="90" y="546" width="250" height="108" rx="16" fill="#dcfce7" stroke="#16a34a" stroke-width="3"/>
|
||||
<text x="215" y="588" text-anchor="middle" fill="#14532d" font-size="27" font-family="Arial, sans-serif" font-weight="700">304</text>
|
||||
<text x="215" y="621" text-anchor="middle" fill="#14532d" font-size="19" font-family="Arial, sans-serif">тело остаётся</text>
|
||||
<rect x="380" y="546" width="250" height="108" rx="16" fill="#fee2e2" stroke="#dc2626" stroke-width="3"/>
|
||||
<text x="505" y="588" text-anchor="middle" fill="#7f1d1d" font-size="27" font-family="Arial, sans-serif" font-weight="700">200</text>
|
||||
<text x="505" y="621" text-anchor="middle" fill="#7f1d1d" font-size="19" font-family="Arial, sans-serif">новый HTML</text>
|
||||
<path d="M505 654v50" stroke="#334155" stroke-width="5" marker-end="url(#arrow)"/>
|
||||
|
||||
<rect x="110" y="708" width="500" height="120" rx="16" fill="#ede9fe" stroke="#7c3aed" stroke-width="3"/>
|
||||
<text x="360" y="752" text-anchor="middle" fill="#4c1d95" font-size="25" font-family="Arial, sans-serif" font-weight="700">HTML ссылается на новый asset URL</text>
|
||||
<text x="360" y="789" text-anchor="middle" fill="#4c1d95" font-size="20" font-family="Arial, sans-serif">/assets/app.4f91.js вместо app.1120.js</text>
|
||||
<path d="M360 828v52" stroke="#334155" stroke-width="5" marker-end="url(#arrow)"/>
|
||||
|
||||
<rect x="110" y="884" width="500" height="102" rx="16" fill="#e0f2fe" stroke="#0284c7" stroke-width="3"/>
|
||||
<text x="360" y="925" text-anchor="middle" fill="#0c4a6e" font-size="25" font-family="Arial, sans-serif" font-weight="700">Asset: public, max-age=31536000</text>
|
||||
<text x="360" y="957" text-anchor="middle" fill="#0c4a6e" font-size="19" font-family="Arial, sans-serif">длинный TTL безопасен из-за нового ключа</text>
|
||||
|
||||
<rect x="110" y="1028" width="500" height="92" rx="16" fill="#ecfccb" stroke="#65a30d" stroke-width="3"/>
|
||||
<text x="360" y="1058" text-anchor="middle" fill="#365314" font-size="24" font-family="Arial, sans-serif" font-weight="700">API: короткая свежесть</text>
|
||||
<text x="360" y="1084" text-anchor="middle" fill="#365314" font-size="22" font-family="Arial, sans-serif" font-weight="700">по допустимой давности</text>
|
||||
<text x="360" y="1110" text-anchor="middle" fill="#365314" font-size="18" font-family="Arial, sans-serif">не смешивать с персональным ответом</text>
|
||||
|
||||
<defs>
|
||||
<marker id="arrow" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse">
|
||||
<path d="M0 0L10 5L0 10z" fill="#334155"/>
|
||||
</marker>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.7 KiB |
@@ -0,0 +1,52 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 720 1160" role="img" aria-labelledby="title desc">
|
||||
<title id="title">Проверка cache key для русского и английского варианта</title>
|
||||
<desc id="desc">Вертикальная схема показывает два запроса к origin и CDN с разным Accept-Language, отдельные варианты по Vary и проверку ETag только внутри одного языкового варианта.</desc>
|
||||
<rect width="720" height="1160" fill="#f8fafc"/>
|
||||
<rect x="42" y="34" width="636" height="108" rx="18" fill="#312e81"/>
|
||||
<text x="360" y="78" text-anchor="middle" fill="#fff" font-size="28" font-family="Arial, sans-serif" font-weight="700">Один URL, два проверяемых варианта</text>
|
||||
<text x="360" y="112" text-anchor="middle" fill="#ddd6fe" font-size="20" font-family="Arial, sans-serif">Меняем только Accept-Language</text>
|
||||
|
||||
<rect x="66" y="192" width="258" height="116" rx="16" fill="#e0f2fe" stroke="#0284c7" stroke-width="3"/>
|
||||
<text x="195" y="235" text-anchor="middle" fill="#0c4a6e" font-size="24" font-family="Arial, sans-serif" font-weight="700">GET /catalog</text>
|
||||
<text x="195" y="270" text-anchor="middle" fill="#0c4a6e" font-size="20" font-family="Arial, sans-serif">Language: ru</text>
|
||||
<rect x="396" y="192" width="258" height="116" rx="16" fill="#fce7f3" stroke="#db2777" stroke-width="3"/>
|
||||
<text x="525" y="235" text-anchor="middle" fill="#831843" font-size="24" font-family="Arial, sans-serif" font-weight="700">GET /catalog</text>
|
||||
<text x="525" y="270" text-anchor="middle" fill="#831843" font-size="20" font-family="Arial, sans-serif">Language: en</text>
|
||||
<path d="M195 308v46" stroke="#334155" stroke-width="5" marker-end="url(#arrow)"/>
|
||||
<path d="M525 308v46" stroke="#334155" stroke-width="5" marker-end="url(#arrow)"/>
|
||||
|
||||
<rect x="82" y="358" width="556" height="122" rx="16" fill="#fef3c7" stroke="#d97706" stroke-width="3"/>
|
||||
<text x="360" y="402" text-anchor="middle" fill="#78350f" font-size="24" font-family="Arial, sans-serif" font-weight="700">Origin возвращает два представления</text>
|
||||
<text x="360" y="437" text-anchor="middle" fill="#78350f" font-size="20" font-family="Arial, sans-serif">Vary: Accept-Language; ETag различается</text>
|
||||
<path d="M360 480v48" stroke="#334155" stroke-width="5" marker-end="url(#arrow)"/>
|
||||
|
||||
<rect x="66" y="532" width="258" height="130" rx="16" fill="#dbeafe" stroke="#2563eb" stroke-width="3"/>
|
||||
<text x="195" y="575" text-anchor="middle" fill="#1e3a8a" font-size="23" font-family="Arial, sans-serif" font-weight="700">CDN key: /catalog + ru</text>
|
||||
<text x="195" y="612" text-anchor="middle" fill="#1e3a8a" font-size="18" font-family="Arial, sans-serif">русское тело</text>
|
||||
<rect x="396" y="532" width="258" height="130" rx="16" fill="#fce7f3" stroke="#db2777" stroke-width="3"/>
|
||||
<text x="525" y="575" text-anchor="middle" fill="#831843" font-size="23" font-family="Arial, sans-serif" font-weight="700">CDN key: /catalog + en</text>
|
||||
<text x="525" y="612" text-anchor="middle" fill="#831843" font-size="18" font-family="Arial, sans-serif">английское тело</text>
|
||||
<path d="M195 662v50" stroke="#334155" stroke-width="5" marker-end="url(#arrow)"/>
|
||||
<path d="M525 662v50" stroke="#334155" stroke-width="5" marker-end="url(#arrow)"/>
|
||||
|
||||
<rect x="82" y="716" width="556" height="118" rx="16" fill="#ecfccb" stroke="#65a30d" stroke-width="3"/>
|
||||
<text x="360" y="760" text-anchor="middle" fill="#365314" font-size="24" font-family="Arial, sans-serif" font-weight="700">После срока: проверить тот же вариант</text>
|
||||
<text x="360" y="796" text-anchor="middle" fill="#365314" font-size="20" font-family="Arial, sans-serif">If-None-Match для ru не проверяет en</text>
|
||||
<path d="M360 834v48" stroke="#334155" stroke-width="5" marker-end="url(#arrow)"/>
|
||||
|
||||
<rect x="80" y="886" width="256" height="106" rx="16" fill="#dcfce7" stroke="#16a34a" stroke-width="3"/>
|
||||
<text x="208" y="930" text-anchor="middle" fill="#14532d" font-size="24" font-family="Arial, sans-serif" font-weight="700">304</text>
|
||||
<text x="208" y="963" text-anchor="middle" fill="#14532d" font-size="18" font-family="Arial, sans-serif">вариант не менялся</text>
|
||||
<rect x="384" y="886" width="256" height="106" rx="16" fill="#fee2e2" stroke="#dc2626" stroke-width="3"/>
|
||||
<text x="512" y="930" text-anchor="middle" fill="#7f1d1d" font-size="24" font-family="Arial, sans-serif" font-weight="700">200</text>
|
||||
<text x="512" y="963" text-anchor="middle" fill="#7f1d1d" font-size="18" font-family="Arial, sans-serif">новый ETag и тело</text>
|
||||
|
||||
<rect x="80" y="1040" width="560" height="56" rx="14" fill="#fff7ed" stroke="#ea580c" stroke-width="3"/>
|
||||
<text x="360" y="1076" text-anchor="middle" fill="#7c2d12" font-size="19" font-family="Arial, sans-serif">Сначала origin, потом edge: не смешивать две границы</text>
|
||||
|
||||
<defs>
|
||||
<marker id="arrow" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse">
|
||||
<path d="M0 0L10 5L0 10z" fill="#334155"/>
|
||||
</marker>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.2 KiB |