Последние системные картыHTML5
Когда задействованы все теги, сортировать по<link>
а также<script>
При маркировке я случайно подумал о проблеме, которая меня давно беспокоит, т. е. об общем<script>
помещать<body>
хвостик,<link>
этикетка на<head>
внутри, пока страница проходитCDN
Когда вводится сторонняя платформа или библиотека, это в основном<script>
этикетка на<link>
перед этикеткой.
Возможно, этот метод стал условностью, но в чем его преимущества, или почему другие методы не желательны, у вас должен быть тот же вопрос, что и у меня, тогда давайте посмотрим вниз.
Готов к работе
Первая подготовительная работа, которую нужно сделать, это собрать сервер, цель – вернутьcss
стиль иjs
script, и пусть сервер возвращает данные с фиксированной задержкой в соответствии с переданными параметрами.
Его структура каталогов выглядит следующим образом, гдеindex.js
а такжеstyle.css
данные, используемые для возврата,app.js
запустить файл для сервера,index.html
является файлом, используемым для тестового примера, остальные файлы или папки можно игнорировать.
├── static
│ ├── index.js
│ ├── style.css
├── app.js
├── index.html
├── package.json
├── node_modules/
Также публикуется соответствующий задействованный код, что удобно для копирования и отладки. Необходимо пояснить, что запуск локальноnode app.js
После запуска браузер типаhttp://127.0.0.1:3000/
может получить доступindex.html
, при доступеstyle.css
может войтиhttp://127.0.0.1:3000/static/style.css?sleep=3000
,вsleep
параметры можно свободно контролироватьcss
Задержка возврата файлов, например, получение файлов5s
установить после возвращенияsleep=5000
.
// app.js
const express = require('express')
const fs = require('fs')
const app = new express()
const port = 3000
const sleepFun = time => {
return new Promise(res => {
setTimeout(() => {
res()
}, time)
})
}
const filter = (req, res, next) => {
const { sleep } = req.query || 0
if (sleep) {
sleepFun(sleep).then(() => next())
} else {
next()
}
}
app.use(filter)
app.use('/static/', express.static('./static/'))
app.get('/', function (req, res, next) {
fs.readFile('./index.html', 'UTF-8', (err, data) => {
if (err) return
res.send(data)
})
})
app.listen(port, () => {
console.log(`app is running at http://127.0.0.1:${port}/`)
})
// static/index.js
var p = document.querySelector('p')
console.log(p)
// static/style.css
p {
color: lightblue;
}
а потомindex.html
препараты, которыеHTML
Часть полки похожа на ту, что внизу, тут надо просто запомнитьDOMContentLoaded
Мероприятие будет на страницеDOM
Запускается после завершения синтаксического анализа.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<script>
document.addEventListener('DOMContentLoaded', () => {
var p = document.querySelector('p')
console.log(p)
})
</script>
</head>
<body>
<p>hello world</p>
</body>
</html>
CSS не блокирует синтаксический анализ DOM, но блокирует рендеринг DOM.
Первый вindex.html
Вставьте следующим образом<link>
тег, а затем введите в браузереhttp://127.0.0.1:3000/
Посетите эту страницу.
<head>
<script>
document.addEventListener('DOMContentLoaded', () => {
var p = document.querySelector('p')
console.log(p)
})
</script>
<link rel="stylesheet" href="./static/style.css?sleep=3000">
</head>
<body>
<p>hello world</p>
</body>
Страница изначально пуста, и консоль выводитp
элемент при загрузке на вкладке браузераloading
,3s
На оборотной стороне изображен светло-голубойhello world
.
Приведенная выше ситуация также показывает, чтоCSS
не блокируетDOM
разбор, если мы говоримCSS
блокироватьDOM
разобрал, тоp
теги не анализируются, поэтомуDOM
не будет разобран,CSS
Невозможно запустить во время процесса запросаDOMContentLoaded
мероприятие. И вcss
Во время запроса консоль сразу выводитp
элемент, поэтомуCSS
не блокируетDOM
анализ.
Другая ситуация заключается в том, что хотяDOM
анализируется очень рано, ноp
Метка задерживается при отображении, потому чтоCSS
Стиль не был запрошен и завершен, после того, как стиль полученhello world
визуализируется, поэтомуCSS
заблокирует рендеринг страницы.
кратко объясните процесс синтаксического анализа и рендеринга в браузере, синтаксический анализDOM
генерироватьDOM Tree
, разборCSS
генерироватьCSSOM Tree
, сочетание этих двух даетrender tree
Дерево рендеринга, и, наконец, браузер отображает страницу в соответствии с деревом рендеринга. Отсюда видно, чтоDOM Tree
анализ иCSSOM Tree
Синтаксический анализ не зависит друг от друга, и они параллельны. следовательноCSS
Не блокирует страницыDOM
, но из-заrender tree
Сборка зависит отDOM Tree
а такжеCSSOM Tree
, следовательноCSS
привязан к блокировкеDOM
рендеринг.
Строго говоря,CSS
заблокируетrender tree
генерация, которая, в свою очередь, блокируетDOM
рендеринг.
JS блокирует парсинг DOM
Во избежание загрузкиCSS
Помехи, вызванные следующим, касаются толькоJS
осуществлениеfor
Логика в теле цикла пока не рассматривается, просто пустьJS
Выполняйте больше времени.
<head>
<script>
document.addEventListener('DOMContentLoaded', () => {
var p = document.querySelector('p')
console.log(p)
})
</script>
</head>
<body>
<script>
const p = document.querySelector('p')
console.log(p)
for (var i = 0, arr = []; i < 100000000; i++) {
arr.push(i)
}
</script>
<p>hello world</p>
</body>
Страница доступа к браузеру, изначально пустая и распечатываемая в консолиnull
, браузерloading
После небольшой задержки консоль печатаетp
Метка отображается одновременно со страницейhello world
.
Вышеприведенная ситуация легко объяснимаJS
заблокируетDOM
проанализировано,JS
Выполнить первоначальную консольную печатьnull
, потому что в это времяp
Тег не проанализирован,for
Когда цикл выполняется, он может ясно чувствовать, что выполнение занимает много времени и выполнение завершено.p
Разбирается тег, который срабатывает в это времяDOMContentLoaded
событие, консоль выводитp
тег, пока страница отображаетсяhello world
.
Более разумное объяснение состоит в том, что, во-первых, браузер не может знатьJS
Конкретное содержимое , если оно проанализировано первымDOM
,на всякий случайJS
Удалить все внутриDOM
, то браузер занят, поэтому просто приостановите парсингDOM
,Подожди покаJS
После завершения выполнения продолжите синтаксический анализ.
CSS блокирует выполнение JS
следующим образом на страницеJS
Вставить перед скриптом<link>
метка и задержка3s
ПолучатьCSS
стиль.
<head>
<script>
document.addEventListener('DOMContentLoaded', () => {
var p = document.querySelector('p')
console.log(p)
})
</script>
<link rel="stylesheet" href="./static/style.css?sleep=3000">
<script src="./static/index.js"></script>
</head>
<body>
<p>hello world</p>
</body>
пустая начальная страница, браузерloading
нагрузка3s
После этого консоль выводитnull
, затем распечатайтеp
вкладка, а страница отображается голубымp
Этикетка.
Такая ситуация кажетсяCSS
не только заблокированDOM
парсинг, а также блокируетсяDOM
оказывать.
Но сначала подумайте, что блокируетDOM
анализ, который только что был доказанCSS
не блокируетDOM
, поэтому можно толькоJS
заблокированDOM
Разбор. ноJS
Всего две строчки кода, долго не блокируется3s
около времени. Так что есть только одна возможностьCSS
заблокируетJS
исполнение.
Таким образом, выходные результаты также могут быть грубо проанализированы, сначала проанализированы до первого<script>
Этикетка,document
привязатьDOMContentLoaded
событие с последующим разборомlink
тег, запрос браузераCSS
стиль, благодаряCSS
не блокируетDOM
синтаксический анализ, поэтому браузер продолжает синтаксический анализ и находит второй<script>
тег, запрос браузераJS
сценарий, на этот разJS
завершиться, но из-заCSS
все еще получаю,JS
Ему нужно дождаться завершения получения, поэтому его нельзя выполнить немедленно.
и второй<script>
не может быть выполнено немедленно, что приводит к следующемуp
Метка также не может быть проанализирована, причина в том,JS
заблокируетDOM
Разбор. просто подожди, покаCSS
После того, как стиль успешно получен, в это времяJS
Выполнить немедленно, вывод в консольnull
, затем браузер продолжает синтаксический анализ доp
теги, парсинг завершен,DOMContentLoaded
Инициировано событие, вывод на консольp
этикетка, последняя светло-голубаяhello world
Рендеринг на страницу.
На самом деле это имеет смысл, представьте себеJS
Содержимое скрипта должно получитьDOM
элементальCSS
атрибут стиля, еслиJS
хочу получитьDOM
Последний правильный стиль обязательно потребует всехCSS
Загрузка завершена, в противном случае загруженные стили могут быть неправильными или устаревшими. Так что подождите, покаJS
перед сценариемCSS
загрузка завершена,JS
может быть выполнен снова, и независимо отJS
Получается в скриптеDOM
Стиль элемента, это должен делать браузер.
Вернемся к вопросу в начале статьи, так вообще<script>
помещать<link>
Передняя часть этикетки имеет смысл.
JS запустит рендеринг страницы
следующим образомCSS
Режим на странице, где название цвета и егоrgb
Значения светло-зеленыеlightgreen
(rgb(144, 238, 144)
),розовыйpink
(rgb(255, 192, 203)
).
// index.html
<head>
<style>
p {
color: lightgreen;
}
</style>
</head>
<body>
<p>hello</p>
<script src="./static/index.js?sleep=2000"></script>
<p>beautiful</p>
<style>
p {
color: pink;
}
</style>
<script src="./static/index.js?sleep=4000"></script>
<p>world</p>
<style>
p {
color: lightblue;
}
</style>
</body>
// static/index.js
var p = document.querySelector('p')
var style = window.getComputedStyle(p, null)
console.log(style.color)
Изначально страница отображается светло-зеленым цветом.hello
, с последующим2s
сделать розовыйhello beautiful
и консоль печатаетrgb(144, 238, 144)
, а затем снова2s
светло-голубой после рендерингаhello beautiful world
и консоль печатаетrgb(255, 192, 203)
.
Приведенные выше результаты грубо проанализированы, так как браузер сначала анализирует первый<style>
этикетки иhello
текстовыйp
метка, продолжайте синтаксический анализ, чтобы найти первый<script>
метка, за которой следует рендер, так как этот процесс очень быстрый, страница изначально может быть светло-зеленойhello
.
Затем браузер выдаетJS
просить,2s
назадJS
получить полный запуск сейчас консольный выводrgb(144, 238, 144)
,JS
После завершения операции браузер продолжает синтаксический анализ доbeautiful
текстовыйp
этикетка и вторая<style>
label, а затем продолжить синтаксический анализ, чтобы найти второй<script>
label, запуская рендеринг, этот процесс тоже очень быстрый, так что вы можете видеть вывод консоли и рендеринг розового цветаhello beautiful
почти одновременно.
разрешается на второй<script>
тег, браузер не делает запрос (объясните немного),2s
получено послеJS
Сценарий и выполнение, вывод на консольrgb(255, 192, 203)
, затем браузер продолжает синтаксический анализ доworld
текстовыйp
этикетка и третий<style>
лейбл, в это времяDOM
После завершения синтаксического анализа выполняется обычный рендеринг.Этот процесс также очень быстрый, поэтому вы также можете видеть вывод консоли и рендерить светло-голубым цветом.hello beautiful world
почти одновременно.
Теперь, чтобы ответить на вопрос только что, парсинг браузераDOM
, хотя он анализирует строку за строкой, он предварительно загружает внешние ресурсы с тегами ссылок (например, с тегамиsrc
отмечен<script>
тег), и когда тег анализируется, нет необходимости загружать и запускать его напрямую, чтобы повысить эффективность работы. Следовательно, между двумя вышеуказанными выходными результатами будет интервал.2s
ситуацию, а не4s
, потому что браузер предварительно загружает оба вместе<script>
сценарий, первый<script>
Когда скрипт загружается, второй<script>
Скрипт слева2s
загрузка завершена.
И этот вывод объясняет, почемуCSS
заблокируетJS
Настоящую причину выполнения браузер не может знать заранее, конкретное содержание скрипта, поэтому при встрече<script>
тег, вы должны отобразить страницу один раз, чтобы убедиться, что<script>
доступно в скриптеDOM
последний стиль. Если вы решите отрендерить страницу, то все равно останутся незагруженныеCSS
style, вы можете только дождаться его загрузки перед рендерингом страницы.
CSS внутри тела
Рассмотрим более частный случай.
<head>
<script>
document.addEventListener('DOMContentLoaded', () => {
var p = document.querySelector('p')
console.log(p)
})
</script>
</head>
<body>
<p>hello</p>
<link rel="stylesheet" href="./static/style.css?sleep=3000">
<p>world</p>
</body>
По всем вышеизложенным выводам заранее анализируйте бегущие результаты, в первую очередь парсит браузер<script>
сценарий,document
связанныйDOMContentLoaded
событие, то браузер продолжает синтаксический анализ и обнаруживает, что текстhello
изp
этикетки и<link>
тег, инициированный браузеромCSS
просьба, из-заCSS
не блокируетDOM
Анализируя, браузер продолжает анализировать текст какworld
изp
тег, на этом парсинг страницы завершен,DOMContentLoaded
Событие запускает вывод консолиp
Этикетка,3s
Задняя страница отображается светло-голубымhello world
.
Итак, изначально страница пуста и браузерloading
нагрузка3s
После этого консоль выводитp
вкладка, а страница отображается голубымhello world
.
Но на самом деле результат не такой, давайте сначала посмотримChrome
производительность в браузере.
Посмотри сноваFirefox
производительность в браузере.
Посмотрите позжеOpera
производительность в браузере.
IE11
и производительность следующих браузеров.
Edge
производительность в браузере.
Как это?5
браузер3
проявления, и ни одно из проявлений не соответствовало предварительно проанализированным.
На самом деле причина такой разницы — так называемое мерцание браузерного стиля (FOUC,Flash of Unstyled Content
)Феномен.
Из-за несоответствия архитектуры движка браузера браузер парситBody
внутриCSS
, движок браузера может сделать выбор.
Один из вариантов – это может бытьCSS
приостановить последующее наблюдениеDOM
анализ, вCSS
Продолжить синтаксический анализ после завершения загрузки, эта ситуация вызоветCSS
блокироватьDOM
парсинг, в результате чего страницаDOM
Парсинг и отрисовка его стиля задерживаются, и это представление такое же, какJS
ситуация похожая.
Другим вариантом является то, что он также доступен по запросуCSS
Продолжить анализ позже, когдаCSS
загружен сDOM
Параллельный разбор, ожидание, покаCSS
Обновите стиль после завершения загрузки.В этом случае некоторыеDOM
Стиль немедленно перейдет от стиля по умолчанию к состоянию стиля, что приведет к миганию стиля.
Это резюме не должно быть слишком запутанным, просто помнитеBody
внутриCSS
Из-за различий в браузерах будут представлены разные формы представления, и это явление обычно называютFOUC
, код должен попытаться избежать этой ситуации.
В итоге
Суммируя все вышеизложенное, можно сделать следующие выводы.
-
CSS
не блокируетDOM
Разобрать, но заблокируетDOM
Рендеринг, более строго,CSS
заблокируетrender tree
генерация, которая, в свою очередь, блокируетDOM
оказание -
JS
заблокируетDOM
Разобрать -
CSS
заблокируетJS
исполнение - браузер встречает
<script>
этикетка и нетdefer
илиasync
свойство вызовет отрисовку страницы -
Body
внутренняя ссылкаCSS
более особенный, сформируетFOUC
явление, пожалуйста, используйте с осторожностью
🎉 Напишите в конце
🍻Ребята, если вы это видели и считаете, что эта статья была вам полезна, ставьте лайк 👍 илиStar✨Поддержите!
Кодирование вручную, если есть ошибки, исправьте их в комментариях 💬~
Ваша поддержка — самая большая мотивация для меня обновляться💪~
GitHub,Blog,Наггетс,CSDNСинхронизированное обновление, подписывайтесь 😉~