小知识,大挑战!本文正在参与“程序员必备小知识”创作活动
script元素
工作原理
浏览器加载javascript脚本,主要通过<script>元素完成,正常的网页加载流程是这样的:
- 浏览器一边下载HTML网页,一边开始解析,也就是说,不等下载完就开始解析
- 解析过程中发现
<script>元素,就暂停解析html,将网页渲染的控制权交给javascript引擎 - 如果
<script>引用的外部脚本,就先下载该js脚本再执行该js,否则就直接执行代码 - javascrip引擎执行js完毕后,控制权交还给渲染引擎,恢复往下解析html网页 总结:加载外部脚本时,页面渲染停止,等待脚本下载并执行完成,再继续渲染,原因时JavaScript可以修改DOM ,渲染引擎和JavaScript引擎时互斥的;
defer和async
如果外部脚本加载时间很长(一直无法完成下载),那么浏览器就会一直等待脚本下载完成,造成网页长时间失去响应,浏览器就会呈现“假死”状态,这被称为“阻塞效应”,为了解决这个问题,可以使用defer或async
| 普通script | defer | async | |
|---|---|---|---|
| 总结 | html暂停,下载并执行 | 并行下载,html解析完成执行 | 并行下载,下载完就执行(执行的时候html暂停) |
| 过程描述 | 1. 浏览器开始解析html 2.发现 <script>暂停解析html3.下载脚本并执行,执行完毕继续解析html | 1. 浏览器开始解析html 2. 发现带有defer的 <script>3. 继续解析html,同时并行下载脚本 4. html解析完成,执行已下载完成的脚本(执行顺序时页面书写顺序) | 1. 浏览器开始解析html 2. 发现带有async的 <script>3. 继续解析html,同时并行下载脚本 4. 脚本下载完成,暂停解析html,执行脚本(哪个先下载完就先执行那个,无法保证脚本执行顺序) 5. 脚本执行完毕,恢复解析html |
| 适用场景 | 脚本之间有依赖关系 | 脚本之间没有依赖关系 |
同源策略
浏览器同源策略,同源:协议,域名,端口 非同源,共有三种行为受到限制:
- 无法读取非同源网页的cookie,LocalStorage和IndexedDB
- 无法接触非同源网页的DOM
- 无法向非同源地址发送AJAX请求(可以发送,但浏览器会拒绝接受响应)
AJAX
同源政策规定,ajax请求只能发给同源的网址,否则就报错 除了架设服务器代理(浏览器请求同源服务器,再由后者请求外部服务),有三种方法规避这个限制:
- JSONP
- WebSocket
- CORS
CORS 通信
wangdoc.com/javascript/… CORS 是一个W3C标准,全程是“跨域资源共享”,他允许浏览器向跨域的服务器发出
XMLHttpRequest请求,从而克服了ajax只能同源使用的限制。 浏览器一旦发现Ajax请求跨域,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感知,因此,实现cors通信的关键是服务器,只要服务器实现了cors接口,就可以跨域通信
两种请求
cors请求分为两类:简单请求和非简单请求 同事满足以下两个条件,就属于简单请求
- 请求方法是以下三种方法之一
- HEAD
- GET
- POST
- HTTP头信息不超出以下几种字段
- Accept
- Accept-Lanauage
- Content-Lanauge
- Last-Event-ID
- Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
凡是不能同时满足以上两个条件,就属于非简单请求。一句话,简单请求就是简单的http方法与简单的http头信息的结合
简单请求
graph TB
A[简单请求] -->E[浏览器:直接发出CORS请求,就是在头部信息中加入Origin字段] --> B{"服务器:判断origin指定的源是否在<br />许可范围内?"}
B -->|不在许可范围| C["服务器:返回一个正常的http回应<br />(不包含Access-Control-Allow-Origin字段)"]
B -->|在许可范围| D["服务器:返回的响应会多几个头部信息<br/>Access-Control-Allow-Origin,Access-Control-Allow-Credentials"]
(1)Access-Control-Allow-Origin
该字段是必须的。它的值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的请求。
(2)Access-Control-Allow-Credentials
该字段可选。它的值是一个布尔值,表示是否允许发送 Cookie。默认情况下,Cookie 不包括在 CORS 请求之中。若要发送cookie,需同时满足一下三个条件:
- 响应头中Access-Control-Allow-Credentials为ture
- 请求头中withCredentials为true
- Access-Control-Allow-Origin就不能设为星号,必须指定明确的、与请求网页一致的域名
非简单请求
graph TB
A[非简单请求 put http://a.com/cors] -->E["浏览器:正式通信之前,增加一次HTTP查询请求,预检请求<br />询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些 HTTP 方法和头信息字段"] --> G["OPTIONS /cors HTTP/1.1<br/>
Origin: http://a.com<br/>
Access-Control-Request-Method: PUT 正式请求的方法<br/>
Access-Control-Request-Headers: X-Custom-Header 正式请求的头部"]
G -->B{"服务器:是否同意预检请求?"}
B -->F["服务器:返回响应,说明服务器允许的范围<br/>Access-Control-Allow-Methods:服务器允许的跨域请求的方法<br/>Access-Control-Allow-Header:服务器允许的头部字段<br/>Access-Control-Max-Age:本次预检有效期,有效期内不用再发送预检请求"]
F -->|同意| C["浏览器:正式发送请求"]
F -->|不同意| D["浏览器:控制台会报出错误说明为什么不同意<br/>(请求的方法,头部信息,域名不在服务器允许范围内就会不同意)"]