不同脚本位置和 link 标签的浏览器呈现行为不同
Browser different rendering behavior with different location of script and link tag
我正在尝试了解 HTML 在浏览器屏幕上呈现的确切时间。
我阅读了 this S.O. 答案并尝试了一些用例,我观察到一些不适合 link、
中共享的模型的内容
我似乎也找不到一个一致的观察模型。
适合所讨论案例的浏览器呈现顺序是什么?
案例A: Image-A
- 当HTML解析器到达M1时,显示M1。
- 然后解析器到达脚本标记,它等待 js 文件下载和解析。
- 然后解析器到达M3,显示M3。
案例 A 与大多数答案中描述的顺序不一致。
哇!让我们继续。
案例 B: 图片-B
- HTML 解析器到达 M1,M1 未显示为案例 A
- HTML 解析器到达 link 标记,它等待 css 下载和解析。
- 显示M1和M2,所以在渲染M1之前等待样式表下载。
- 然后解析器到达脚本标记,它等待 js 文件下载和解析。
- 然后解析器到达M3,显示M3。
所以 Case-B 显示它没有渲染 M1,它在渲染之前等待 CSS 下载。
所以可能渲染器在渲染之前需要知道CSS。
案例:C 图片 C
所以从案例 B 中,我们假设渲染器可能需要知道 CSS。
让我们看看案例 C:
- HTML解析器到达M1,显示M1。 它不应该显示,因为正如我们在案例 B 中看到的那样,它应该等待 css 加载 。
- 现在解析器到达脚本,它等待 js 下载和解析。
- 显示M2、M3
编辑:
提出的解释上述行为的思维模型..(但需要 review/refinement)
Script
不是呈现器阻止标记
link
是渲染器阻塞标签
- 考虑到 renderer 和 HTML parser 是两个线程。
- HTML 解析器可以将内容发送到渲染器进行渲染。
- HTML 解析器可以向渲染器发送块信号.. 以阻止渲染器渲染任何 html 至少没有被渲染过一次。
- HTML 解析器可以向渲染器发送取消阻止信号.. 以取消阻止渲染器渲染任何未渲染过的 html。
利用上述模型,我们可以解释案例 B 和案例 C:
案例 B 解释:
- HTML 解析器到达 M1,M1 被发送到渲染器。
- HTML 解析器到达 Link 标记,解析器向渲染器发送阻塞信号。
- 渲染器在渲染 M1 之前,它收到了一个阻塞信号,因此 M1 没有显示。
- HTML解析器完成link标签解析(下载)并向渲染器发送解锁信号,在接收到解锁信号后渲染M1。
- HTML 解析器到达 M2,M2 被发送到渲染器。
- HTML解析器到达Script标签,由于script标签不是渲染器阻塞标签,渲染器可以自由渲染html。
- HTML解析器完成脚本标签的解析(下载)。
- HTML 解析器到达 M3,M3 被发送到渲染器。
同样我们可以晒运行CASE C,完全符合上面的模型
我的模型是正确的还是有问题?
你几乎是对的。
除了它更简单 - 渲染器是被动的并且不接收 "blocking signal"。
它不会呈现(更新显示以反映 dom 树)直到有人要求它。
您的 HTML 无效 - 您不能将 <link rel=...>
放入正文。 (生活HTML4.2.4)
如您所想,样式表是一种 render-blocking 资源 - 它会阻止呈现内容,
与将暂停并呈现已解析内容的脚本相反。
以下是我的解释:
案例 B:M1 - stylesheet - M2 - script - M3
- 浏览器获取 HTML。 M1 进入 DOM 树。 M1还没有显示,renderer还没被要求工作
- 样式表加载。 (实际上它阻止了 M1 渲染)
- 样式表完成。 M1 仍然没有显示。 (还有两步)
- M2 进入 DOM 树。 M1和M2还没有显示。
- 脚本触发渲染,从而显示 M1 和 M2,然后加载。
- 脚本完成。没有任何变化(就本例而言)。
- M3进入DOM树,尚未显示。
- 文档完成,页面渲染完成,显示M3。
These behaviours are intentional.
Once upon a time, js was slow and scripts took long time to run,
whereas stylesheets was (and still is) important for hiding elements by default.
Time may have changed, but these behaviours are unlikely to change.
案例 C:M1 - script - M2 - link - M3
- 浏览器获取 HTML。 M1 进入 DOM 树。 M1暂未显示
- 脚本触发渲染,从而显示 M1,然后加载。
- 脚本完成。没有任何变化。
- M2 进入 DOM 树。还没有显示。
- 加载样式表,实际上阻止了 M2。
- 样式表完成。 M2还是没有显示。
- M3进入DOM树,尚未显示。
- 文档已完成,页面已呈现,M2 和 M3 已显示。
The actual display process, in term of threads, is very complicated, and in some sense greatly varies by browser.
For example, DOM is not thread safe.
Think about what that means.
To keep it simple, you can imagine browser processing as data and event flowing between the various modules.
Here are some Firefox rendering subsystems:
我正在尝试了解 HTML 在浏览器屏幕上呈现的确切时间。
我阅读了 this S.O. 答案并尝试了一些用例,我观察到一些不适合 link、
中共享的模型的内容
我似乎也找不到一个一致的观察模型。
适合所讨论案例的浏览器呈现顺序是什么?
案例A: Image-A
- 当HTML解析器到达M1时,显示M1。
- 然后解析器到达脚本标记,它等待 js 文件下载和解析。
- 然后解析器到达M3,显示M3。
案例 A 与大多数答案中描述的顺序不一致。 哇!让我们继续。
案例 B: 图片-B
- HTML 解析器到达 M1,M1 未显示为案例 A
- HTML 解析器到达 link 标记,它等待 css 下载和解析。
- 显示M1和M2,所以在渲染M1之前等待样式表下载。
- 然后解析器到达脚本标记,它等待 js 文件下载和解析。
- 然后解析器到达M3,显示M3。
所以 Case-B 显示它没有渲染 M1,它在渲染之前等待 CSS 下载。 所以可能渲染器在渲染之前需要知道CSS。
案例:C 图片 C
所以从案例 B 中,我们假设渲染器可能需要知道 CSS。
让我们看看案例 C:
- HTML解析器到达M1,显示M1。 它不应该显示,因为正如我们在案例 B 中看到的那样,它应该等待 css 加载 。
- 现在解析器到达脚本,它等待 js 下载和解析。
- 显示M2、M3
编辑: 提出的解释上述行为的思维模型..(但需要 review/refinement)
Script
不是呈现器阻止标记link
是渲染器阻塞标签- 考虑到 renderer 和 HTML parser 是两个线程。
- HTML 解析器可以将内容发送到渲染器进行渲染。
- HTML 解析器可以向渲染器发送块信号.. 以阻止渲染器渲染任何 html 至少没有被渲染过一次。
- HTML 解析器可以向渲染器发送取消阻止信号.. 以取消阻止渲染器渲染任何未渲染过的 html。
利用上述模型,我们可以解释案例 B 和案例 C:
案例 B 解释:
- HTML 解析器到达 M1,M1 被发送到渲染器。
- HTML 解析器到达 Link 标记,解析器向渲染器发送阻塞信号。
- 渲染器在渲染 M1 之前,它收到了一个阻塞信号,因此 M1 没有显示。
- HTML解析器完成link标签解析(下载)并向渲染器发送解锁信号,在接收到解锁信号后渲染M1。
- HTML 解析器到达 M2,M2 被发送到渲染器。
- HTML解析器到达Script标签,由于script标签不是渲染器阻塞标签,渲染器可以自由渲染html。
- HTML解析器完成脚本标签的解析(下载)。
- HTML 解析器到达 M3,M3 被发送到渲染器。
同样我们可以晒运行CASE C,完全符合上面的模型
我的模型是正确的还是有问题?
你几乎是对的。 除了它更简单 - 渲染器是被动的并且不接收 "blocking signal"。 它不会呈现(更新显示以反映 dom 树)直到有人要求它。
您的 HTML 无效 - 您不能将
<link rel=...>
放入正文。 (生活HTML4.2.4)如您所想,样式表是一种 render-blocking 资源 - 它会阻止呈现内容, 与将暂停并呈现已解析内容的脚本相反。
以下是我的解释:
案例 B:M1 - stylesheet - M2 - script - M3
- 浏览器获取 HTML。 M1 进入 DOM 树。 M1还没有显示,renderer还没被要求工作
- 样式表加载。 (实际上它阻止了 M1 渲染)
- 样式表完成。 M1 仍然没有显示。 (还有两步)
- M2 进入 DOM 树。 M1和M2还没有显示。
- 脚本触发渲染,从而显示 M1 和 M2,然后加载。
- 脚本完成。没有任何变化(就本例而言)。
- M3进入DOM树,尚未显示。
- 文档完成,页面渲染完成,显示M3。
These behaviours are intentional. Once upon a time, js was slow and scripts took long time to run, whereas stylesheets was (and still is) important for hiding elements by default. Time may have changed, but these behaviours are unlikely to change.
案例 C:M1 - script - M2 - link - M3
- 浏览器获取 HTML。 M1 进入 DOM 树。 M1暂未显示
- 脚本触发渲染,从而显示 M1,然后加载。
- 脚本完成。没有任何变化。
- M2 进入 DOM 树。还没有显示。
- 加载样式表,实际上阻止了 M2。
- 样式表完成。 M2还是没有显示。
- M3进入DOM树,尚未显示。
- 文档已完成,页面已呈现,M2 和 M3 已显示。
The actual display process, in term of threads, is very complicated, and in some sense greatly varies by browser. For example, DOM is not thread safe. Think about what that means.
To keep it simple, you can imagine browser processing as data and event flowing between the various modules. Here are some Firefox rendering subsystems: