【搞发🌸活】不信书上那套理论!亲测Javascript能卡浏览器Reader一辈子~

点进来的前端佬,先别走!

让我详细给你逼逼叨!

在很久很久以前,前端圈就广泛流传,Javascript的加载和执行,都会阻塞浏览器Render。

然后过了这些日子,作为一名优秀的前端佬的意识爆发。

按照上面的说法,那是不是可以构造一个Javascript程序,让后续的CSS以及HTML文本永远都不能被解析Render到?

喔,觉的挺来劲的,说干就干!

前言

一开始构建了这么一个HTML,如下:

html 复制代码
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>demo</title>
</head>
<body>
  <h1 id="start" class="h1-title">开始渲染了</h1>
  <script>
    console.log(document.getElementById('start'))
  </script>
</body>
</html>
<script>
  // 此处插入代码
</script>
<h1 class="h1-title">看到这里就失败了!</h1>
<style>
  .h1-title {
    color: red;
  }
</style>

预想阻塞js代码会写在script标签里。

以上代码运行后如下:

以上展示的,因为没有填入代码,符合期望。

这里解释下为什么要将script脚本和h1要放在html之外。

因为根据各个资料上说,浏览器解读HTML文本就是从上往下解析的。当遇到</html>文档结束标签,就会开始生成DOM树+CSSOM树,并开始Render。

那我脑袋一拍,灵光一闪,自以为是的将需要Render的HTML和CSS放在</html>后,期望只Render第一行文字开始渲染了,而第二行文字看到这里就失败了!就永远得不到Render。

开始挑战!!!

方法一 递归

脑子第一个蹦出来的方法,就是用递归,来模拟JavaScript阻塞。

在上面HTML模板中填入如下代码:

js 复制代码
function block() {
  Math.sqrt(Math.random());
  block();
}
block();

结果如下:

失败了,还在控制器里报了一个错误.RangeError: Maximum call stack size exceeded

oh,shit,明显这里我忽略了一个细节。

大家都知道的,Javascript是单线程运行机制。

而Javascript的函数分为解析和调用。解析有一个入栈的过程,调用有一个出栈过程。当入栈停止后,才会出栈被调用执行。而上面递归代码,构造了一个无限入栈的场景,结果就是直接撑爆内存。

很显然,浏览器识别到这种风险,直接作出报错处理。

失败~继续尝试!

方法二 while死循环

有了JS的单线程执行思路,顺理成章的,就有了使用while死循环,来模拟阻塞。

插入如下代码试一试。

js 复制代码
while (true) {
  // 持续执行同步任务
  Math.sqrt(Math.random());
}

效果如下:

喔!成功了???? ★,° :.☆( ̄▽ ̄)/$:.°★

其实并没有~

之所以能有上面的效果,在于我使用了VSCODE中的Live Server插件,并构造了特殊的场景。基本原来就是Live Server是有热更新,我动态插入了</html>之后的代码到文件中。

究其原因,在现代浏览器中,浏览器有着强大的纠错机制。很多浏览器都不会遇到</html>就停止解析,忽略后续的文本。他们仍然会好心好意 的将后续能看懂的文本,插入到<body>里去。

所以实际上,正常的去执行上面构造的代码,只能得到如下效果:

但现在离成功,也算走了一半!

动态插入的思路,让我想到了第三个方法。

方法三 按钮手动添加代码

这就是构造一个添加按钮,点击之后,动态添加上HTML标签和Script脚本。

初始是这个样子的:

HTML代码构造如下:

html 复制代码
<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>demo</title>
</head>
<body>
  <h1 id="start" class="h1-title">开始渲染了</h1>
  <button id="execute">添加</button>
  <script>
    function sleepBlocking(ms) {
      const start = Date.now();
      while (Date.now() - start < ms) {
        // 什么都不做,纯粹阻塞
      }
    }
    document.getElementById('execute').onclick = () => {
      now1 = new Date().getTime()
      // 在前
      document.getElementById('execute').insertAdjacentHTML('beforebegin', `
          <h1 class='h1-title'>看到这里就失败了!</h1>
          <style>
            .h1-title {
              color: red;
            }
          <\/style>
        `)
      // 在后
      const script = document.createElement("script");
      // 5秒后执行
      script.innerHTML = 'sleepBlocking(5000);console.log("休眠后", new Date().getTime() - now1)'
      console.log('所有脚本添加后', new Date().getTime() - now1)
      document.body.appendChild(script);
    }
  </script>
</body>
</html>

从上面的代码可以看到,我弄了一个阻塞执行的5秒函数。接下来预期的效果就是:

点击前,先展示黑色的文字开始渲染了

点击添加按钮后,经过5秒后,就会使得所有文字变红,并出现看到这里就失败了!的效果,最终如下图:

符合预期!!完美~

以上就是整个验证的思路了,个人觉的基本可以回答标题上的问题。Javascript是真的会阻塞浏览器Render!!

另外还有一种思路,就是使用stream来构造一个一直会执行的远程脚本,为避免无聊,这里就不尝试了,都是大差不差的。

如果还能看到这里的前端佬,那我想说在这个尝试的过程还有一个意外,就是我们经常会看到很多技术类文档,解说Event Loop,都会用上宏任务和微任务解释,个人觉的有点牵强不太行。感兴趣接着往下看!

方法四 构造永不结束的"宏任务"?

先贴下Event Loop的一些解释:

  1. 从宏任务的头部取出一个任务执行;
  2. 执行过程中若遇到微任务则将其添加到微任务的队列中;
  3. 宏任务执行完毕后,微任务的队列中是否存在任务,若存在,则挨个儿出去执行,直到执行完毕;
  4. GUI 渲染;
  5. 回到步骤 1,直到宏任务执行完毕;

按照上面思路,是不是我我构造一个永远不结束的宏任务,也可以阻塞Render???

现在我把Javascript代码替换成如下:

js 复制代码
function setTime() {
  Math.sqrt(Math.random());
  setTimeout(() => {
     setTime()
  }, 1)
}
setTime()

然后我们看到的效果确实是这样的。

并没有阻止,定时器任务还在依旧运行代码。

所以,我是不太相信网上那些所谓的事件循环的解释了!

另外我自己去找权威书籍《JavaScript高级程序设计(第4版)》 和 《JavaScript权威指南(第7版)》,英文版本,连那些词都没得~

嗯....先这样吧。

看到这里,我是想说,我这篇表情包很克制了!前端佬们给点小心心吧♥(ˆ◡ˆԅ)

相关推荐
西陵2 小时前
Nx带来极致的前端开发体验——任务缓存
前端·javascript·架构
Panda__Panda2 小时前
docker项目打包演示项目(数字排序服务)
运维·javascript·python·docker·容器·c#
10年前端老司机3 小时前
Promise 常见面试题(持续更新中)
前端·javascript
WebDesign_Mu6 小时前
为了庆祝2025英雄联盟全球总决赛开启,我用HTML+CSS+JS制作了LOL官方网站
javascript·css·html
噢,我明白了6 小时前
前端js 常见算法面试题目详解
前端·javascript·算法
学编程的小虎6 小时前
用 Python + Vue3 打造超炫酷音乐播放器:网易云歌单爬取 + Three.js 波形可视化
开发语言·javascript·python
做好一个小前端7 小时前
后端接口获取到csv格式内容并导出,拒绝乱码
前端·javascript·html
携欢7 小时前
PortSwigger靶场之将 XSS 存储到onclick带有尖括号和双引号 HTML 编码以及单引号和反斜杠转义的事件中通关秘籍
前端·html·xss
勤奋菲菲8 小时前
Vue3+Three.js:requestAnimationFrame的详细介绍
开发语言·javascript·three.js·前端可视化