最近遇到一个问题,就是我的个人网站需要接入第三方百度统计,因我的文章图片有来自第三方微信后台上传的文章,所以使用<meta name="referrer" content="no-referrer">解决图片访问403的问题,但是此时这个导致我百度统计失败了,于是去查询了一下referrer这个特性。

正文开始...

referrer

这个主要主要是来防护CORS跨站请求伪造的一个标识,对于来源于自身服务器,会默认在请求头中带入refer信息

什么意思,具体看下下面

当我们在html的header中使用<meta name="referrer" content="no-referrer">

请求头的General

Referrer Policy: no-referrer

request中整个Referer信息会被删除

如果我们没有加meta标签no-referrer

那么此时你会发现默认请求头里是

Status Code: 200 OK
Referrer Policy: strict-origin-when-cross-origin

然后请求头request-header里面就会携带了Referer

Referer: http://localhost:8080/

关于referrer的更多信息可以参考http referer策略open in new window

我的网站需要不带referrer,因为微信图片如果带了当前站点的referrer就会有问题,所以此时怎么加上百度统计代码呢?

由于最初是这样加入统计的

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="referrer" content="no-referrer" />
    <title>js执行顺序</title>

    <style>
      * {
        padding: 0;
        margin: 0;
      }
    </style>
  </head>
  <body>
    <div id="app">
      <h1>js执行顺序</h1>
    </div>
    <script src="https://hm.baidu.com/hm.js?c7002d193ba43df9317b7fc847709213"></script>
  </body>
</html>

这样的做法是我们通用的方式,就是script脚本放入body中,但是这样会导致百度统计不到,因为meta中已经使用no-referrer了,那怎么办呢?我网页中又需要加no-referrer,不加这个,会导致第三方图片显示不出来。

页面渲染

此时我们需要了解另外外一个知识,就是浏览器页面是怎么渲染的

我们写一段测试代码

  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <!-- <meta name="referrer" content="no-referrer" /> -->
    <title>js执行顺序</title>
    <script>
      alert(111);
    </script>
    <style>
      * {
        padding: 0;
        margin: 0;
      }
    </style>
  </head>
  <body>
    <div id="app">
      <h1>js执行顺序</h1>
    </div>
    <script src="https://hm.baidu.com/hm.js?c7002d193ba43df9317b7fc847709213"></script>
  </body>

html页面渲染是根据标签顺序同步渲染的,而且script标签会阻塞Dom的渲染

此时你会看到页面弹框,但是html内容并没有完全渲染出来

当我确认弹框后,页面才显示出来

我们在header中加入一行css代码

   <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <!-- <meta name="referrer" content="no-referrer" /> -->
    <title>js执行顺序</title>
    <style>
      body {
        background-color: red;
      }
    </style>

    <style>
      * {
        padding: 0;
        margin: 0;
      }
    </style>
  </head>
  <body>
    <div id="app">
      <h1>js执行顺序</h1>
    </div>
    <script>
      alert(111);
    </script>
    <script src="https://hm.baidu.com/hm.js?c7002d193ba43df9317b7fc847709213"></script>
  </body>

我们会发现,页面先绘制成了红色,然后再执行script脚本,最后页面内容显示出来了

html标签会按照顺序执行,背景先是变成了红色,然后内容没有立即显示出来,执行script脚本后,才显示了页面内容,这就证明了js会阻塞页面的解析,所以在文章开头,我们要设置referrer,那么我们先执行script统计脚本,然后再设置meta

  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <script src="https://hm.baidu.com/hm.js?c7002d193ba43df9317b7fc847709213"></script>
    <meta name="referrer" content="no-referrer" />
    <title>js执行顺序</title>
    <style>
      body {
        background-color: red;
      }
    </style>

    <style>
      * {
        padding: 0;
        margin: 0;
      }
    </style>
  </head>

所以我们看到百度统计脚本是像正常默认的,但是其他基本就是no-referrer

其他脚本,因为header设置了meta

所以解决百度统计代码失效的办法就是在设置meta之前执行就行

CSS会阻塞页面解析吗

在以前面试中,就曾经有问到这个问题,css到底会不会阻塞dom的解析,这时常是一个令人模糊的问题

举个例子证实一下自己的猜想

新建一个index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>js执行顺序</title>
    <link rel="stylesheet" href="./index.css" />
  </head>
  <body>
    <div class="app">hello word</div>
  </body>
</html>

然后我引入index.css

我在index.css写入测试代码

.app {
  background-color: red;
}
aaa

你会发现,我在css文件中写入了一段非css的代码

但是页面依旧能够正常渲染

所以从以上可以证明,css并不会阻塞是dom解析dom解析css渲染是并行的,css负责渲染标签样式,html只是负责解析内容标签,css渲染html解析主要是在GUI线程里面,GUI线程主要是构建DOM Tree,Style Tree,Render Tree布局以及绘制。

我们经常会在面试中被问到JS为什么是单线程的,有时会被问得哑口无言。

我们想想JS祖师爷在设计这门语言肯定有其初衷和取舍,浏览器是多进程的,浏览器的每一个窗口就是一个进程,而进程之间都应该是互相独立的,而每一个进程里面的线程是独立,所以js设计时就是单线程的,每个线程之间互不影响

所以JS设计就是单线程的,通常来讲为了弥补单线程的缺陷,所以有了同步任务与异步任务的设计,在浏览器渲染页面,解析dom Tree,绘制css tree,通常在主线程执行栈中优先执行同步任务,主线程执行栈执行完了,然后再执行异步任务,异步任务主要会进入队列中,遵循先进先出原则,直到队列执行完毕为止。

css会阻塞js执行吗?

我们做个实验,在style标签前后都引入一段js执行

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <!-- <meta name="referrer" content="no-referrer" /> -->
    <title>js执行顺序</title>
    <script>
      var start = new Date().getTime();
      console.log("before css");
    </script>
    <link rel="stylesheet" href="./index.css" />
    <!-- <link
      href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.2.0/css/bootstrap.css"
      rel="stylesheet"
    /> -->
    <script>
      var end = new Date().getTime();
      console.log(end - start, "difftime");
      console.log("after css");
    </script>
  </head>
  <body>
    <div class="app">hello word</div>
    <script>
      const app = document.getElementsByClassName("app")[0];
      app.style.backgroundColor = "green";
    </script>
  </body>
</html>

引入index.css 引入bootstrap.css

我们引入bootstrap.css与引入我们自己的index.css,自此你会发现,最后执行的时间很明显,引入bootstrap的css打印的时间差明显是要大于体积小的css的

所以css是会阻塞js的执行的

但是一般情况,我们不会这么干,一般都会在header中引入css,在body结束标签引入脚本

也就大概会是下面这样

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="./index.css">
</head>
<body>
    <div id="app"></div>
    <script>
        console.log('hello')
    </script>
</body>
</html>

总结

  • 当你百度统计失效时,如果网站meta使用了no-referrer,如果是在统计脚本之前执行,那么此时需要先执行统计脚本,然后再设置meta

  • js会阻塞dom tree解析,css不会阻塞dom tree解析,css只会影响dom tree的绘制

  • css的加载是会阻塞js的运行的,css体积越小影响越小

  • 外部资源的最佳方式,header引入外链css,body结束标签引入script脚本

  • 本文示例code exampleopen in new window

扫二维码,关注公众号
专注前端技术,分享web技术
加作者微信
扫二维码 备注 【加群】
教你聊天恋爱,助力脱单
微信扫小程序二维码,助你寻他/她
专注前端技术,分享Web技术
微信扫小程序二维码,一起学习,一起进步
前端面试大全
海量前端面试经典题,助力前端面试