我刚刚注意到在执行脚本之前渲染的奇怪行为.我一直认为,浏览器不可能将一个任务从呈现队列中出列,然后在脚本标记之前执行它,因为这是一个单线程.正如你将看到的,这不是真的.下面是一个简单的代码示例:

console.log('SCRIPT EXECUTED')
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <title>HTML</title>

    <script>
        requestAnimationFrame(function animate(time) {
            console.log('RAF', performance.now());
        });
    </script>
</head>

<body>
<h1>Hello world</h1>

<script src="./script.js"></script>
</body>
</html>

在控制台中可能会看到不一致的输出.有时渲染出现在脚本之前,反之亦然.例如,它可能会导致用户界面闪烁.

有人能对此给出有意义的解释吗?

推荐答案

外部classic 脚本为parser-blocking,也就是说,在继续解析文档的其余部分之前,HTML解析器将等待脚本执行.

<script src="data:text/javascript,console.log(document.body.children[document.body.children.length - 1].nodeName);"></script>
<span>Should log SCRIPT and not SPAN</span>

但要达到render-blocking岁,他们必须在文件的第<head>位.

/*
 * Since StackSnippets do wrap the HTML & JS content in the <body>,
 * we use another <iframe> for our demo.
 * But StackSnippet's console isn't available there,
 * so we use postMessage and log from here.
 */
onmessage = ({data}) => console.log(...data);
<iframe srcdoc="
<!DOCTYPE HTML>
<html>
  <head>
    <script>
      requestAnimationFrame(function animate(time) {
        parent.postMessage(['RAF', performance.now()], '*');
      });
    </script>
    <script src='./script'></script>
    <script>
      parent.postMessage(['SCRIPT EXECUTED'], '*')
    </script>
  </head>
  <body>
    <h1>HELLO WORLD</h1>
  </body>
</html>"></iframe>

请注意,Firefox显然还不支持render-blocking.

此外,您可能会对blocking="render"属性感兴趣,该属性允许<script>在为render-blocking时不被解析器阻塞(deferasyncmodule),尽管这目前仅对外部脚本可用,但在不久的将来是this might change.

onmessage = ({data}) => console.log(...data);
/* In Chrome this logs
 * SCRIPT EXECUTED
 * H1
 * "RAF", a number
 */
<iframe srcdoc="
<!DOCTYPE HTML>
<html>
  <head>
    <script>
      requestAnimationFrame(function animate(time) {
        parent.postMessage(['RAF', performance.now()], '*');
      });
    </script>
    <script defer src='data:text/javascript,parent.postMessage([document.body.children[document.body.children.length - 1].nodeName], `*`);'></script>
    <script>
      parent.postMessage(['SCRIPT EXECUTED'], '*')
    </script>
  <head>
  <body>
    <h1>HELLO WORLD</h1>
  </body>
</html>"></iframe>

Javascript相关问答推荐

如何修复循环HTML元素附加函数中的问题?

在React中获取数据后,如何避免不必要的组件闪现1秒?

google docs boldText直到按行执行应用脚本错误

jQuery s data()[storage object]在vanilla JavaScript中?'

在服务器上放置了Create Reaction App Build之后的空白页面

从Node JS将对象数组中的数据插入Postgres表

JS,当你点击卡片下方的绿色空间,而它是在它的背后转动时,

如何将多维数组插入到另一个多维数组中?

material UI按钮组样式props 不反射

在数组中查找重叠对象并仅返回那些重叠对象

查询参数中的JAVASCRIPT/REACT中的括号

使用NextJS+MongoDB+Prisma ORM获取无效请求正文,无法发布错误

在JS中动态创建对象,并将其追加到HTML表中

使用类型:assets资源 /资源&时,webpack的配置对象&无效

try 将Redux工具包与MUI ToggleButtonGroup组件一起使用时出错

无法检索与Puppeteer的蒸汽游戏的Bundle 包价格

在渲染turbo流之后滚动到元素

如何根据查询结果重新排列日期

为什么我看到的是回复,而不是我的文档?

如何在预览中显示html+css与数据URL?