JS学习笔记06-网页扩展

本小节主要记录了网页中一些其余的知识点:javascript

  • 模型
  • 网页对象
  • 存储对象
  • 通讯对象

1、模型

1.1 浏览器模型

浏览器的核心是两部分:渲染引擎和 JavaScript引擎。html

1.1.1 渲染引擎

渲染引擎的主要做用是,将网页代码渲染为用户视觉能够感知的平面文档。渲染引擎处理网页,一般分红四个阶段:java

  1. 解析代码:HTML代码解析为 DOM,CSS代码解析为 CSSOM(CSS Object Model)。
  2. 对象合成:将 DOM和 CSSOM合成一棵渲染树。
  3. 布局:计算出渲染树的布局(layout)。
  4. 绘制:将渲染树绘制到屏幕。

以上四步并不是严格按顺序执行,每每第一步还没完成,第二步和第三步就已经开始了。因此会看到这种状况:网页的HTML代码还没下载完,但浏览器已经显示出内容。web

来看一下很是重要的重流和重绘。渲染树转换为网页布局,称为“布局流”(flow);布局显示到页面的这个过程,称为“绘制”(paint)。它们都具备阻塞效应,而且会耗费不少时间和计算资源。json

页面生成之后,脚本操做和样式表操做都会触发“重流”(reflow)和“重绘”(repaint)。用户的互动也会触发重流和重绘,如改变窗口大小、页面滚动、设置鼠标悬停a:hover效果、在输入框中输入文本等。api

重流和重绘并不必定一块儿发生,重流必然致使重绘,重绘不必定须要重流。好比改变元素颜色,只会致使重绘,而不会致使重流;改变元素的布局,则会致使重绘和重流。大多数状况下,浏览器会智能判断,将重流和重绘只限制到相关的子树上面,最小化所耗费的代价,而不会全局从新生成网页。跨域

做为开发者,应该尽可能设法下降重绘的次数和成本。好比,尽可能不要变更高层的 DOM 元素,而以底层 DOM 元素的变更代替;再好比重绘table布局和flex布局,开销都会比较大。浏览器

1.1.2 JavaScript引擎

JavaScript引擎的主要做用是,读取网页中的JavaScript代码,对其处理后运行。早期浏览器内部对 JavaScript 的处理过程以下:缓存

  1. 对代码进行词法分析,将代码分解成词元。
  2. 对词元进行语法分析,将代码整理成语法树。
  3. 使用翻译器,将代码转为字节码。
  4. 使用解释器,将字节码转为机器码。

逐行所有解释将字节码转为机器码,是很低效的。为了提升运行速度,现代浏览器改成采用“即时编译”(Just In Time compiler,缩写 JIT),即字节码只在运行时编译,用到哪一行就编译哪一行,而且把编译结果缓存(inline cache)。一般一个程序被常常用到的只是其中一小部分代码,有了缓存的编译结果,整个程序的运行速度就会显著提高。服务器

字节码不能直接运行,而是运行在一个虚拟机之上,通常也把虚拟机称为JavaScript引擎。并不是全部的 JavaScript虚拟机运行时都有字节码,有的JavaScript虚拟机基于源码,即只要有可能,就经过 JIT编译器直接把源码编译成机器码运行,省略字节码步骤。这样作的目的,是为了尽量地优化代码、提升性能。

1.2 script 元素

浏览器加载 JavaScript 脚本,主要经过<script>元素完成。正常的网页加载流程是这样的:

  1. 渲染引擎一边下载HTML网页,一边开始解析。
  2. 解析过程当中发现<script>元素后暂停解析,把网页的控制权转交给JavaScript引擎。
  3. JavaScript引擎下载脚本后执行代码。
  4. 执行完毕后,把网页控制权交还渲染引擎,恢复往下解析 HTML 网页。

浏览器会并行下载脚本,可是执行仍是按照定义的顺序来执行。

较好的作法是将<script>标签都放在页面底部而不是头部的缘由以下:

  • 若是外部脚本加载时间很长(一直没法完成下载),那么浏览器就会一直等待脚本下载完成,形成网页长时间失去响应,浏览器就会呈现“假死”状态,这被称为“阻塞效应”。
  • 由于在 DOM 结构生成以前就调用 DOM 节点JS会报错,若是脚本都在网页尾部加载就不存在这个问题。

对于来自同一个域名的资源,好比脚本文件、样式表文件、图片文件等,浏览器通常有限制,同时最多下载6~20个资源,即最多同时打开的 TCP 链接有限制,这是为了防止对服务器形成太大压力。若是是来自不一样域名的资源,就没有这个限制。因此,一般把静态文件放在不一样的域名之下,以加快下载速度。

<script>标签中还常见以下属性:

  • defer属性的做用是延迟脚本的执行,等到 DOM 加载生成后再执行脚本。该属性的运行流程以下:

    1. 渲染引擎一边下载HTML网页,一边开始解析。
    2. 解析过程当中,发现带有defer属性的<script>标签,继续往下解析 HTML 网页,同时开启另外一个进程并行下载<script>元素加载的外部脚本。
    3. 渲染引擎完成解析 HTML 网页,此时再交由JavaScript引擎执行已经下载完成的脚本。

    defer属性能够保证脚本下载的同时,浏览器继续渲染。须要注意的是,一旦采用这个属性,依旧保证脚本的执行顺序。

  • async属性的做用是使用另外一个进程下载脚本,下载时不会阻塞渲染。该属性的运行流程以下:

    1. 渲染引擎一边下载HTML网页,一边开始解析。
    2. 解析过程当中,发现带有async属性的<script>标签,继续往下解析 HTML 网页,同时开启另外一个进程并行下载<script>标签中的外部脚本。
    3. 脚本下载完成,渲染引擎暂停解析 HTML 网页,交由JavaScript引擎执行。
    4. 脚本执行完毕,JavaScript引擎交由渲染引擎恢复解析 HTML 网页。

    async属性能够保证脚本下载的同时,浏览器继续渲染。须要注意的是,一旦采用这个属性,就没法保证脚本的执行顺序。

通常来讲,若是脚本之间有依赖关系,就使用defer属性;若是脚本之间没有依赖关系,就使用async属性。若是同时使用和deferasync属性,浏览器行为由async属性决定。

2、网页对象

2.1 window

window对象指当前的浏览器窗口。它也是当前页面的顶层对象,即最高一层的对象,全部其余对象都是它的下属。

对象属性

网页对象属性

  • window.document:指向document对象
  • window.location:指向Location对象
  • window.localStorage:指向本地储存的localStorage数据
  • window.sessionStorage:指向本地储存的sessionStorage数据

工具对象属性:

  • window.locationbar:地址栏对象,对象的visible属性是一个布尔值,表示该组件是否可见。
  • window.menubar:菜单栏对象,对象的visible属性是一个布尔值,表示该组件是否可见。
  • window.toolbar:工具栏对象,对象的visible属性是一个布尔值,表示该组件是否可见。
  • window.statusbar:状态栏对象,对象的visible属性是一个布尔值,表示该组件是否可见。

对象事件

window.onload属性事件发生在文档在浏览器窗口加载完毕时

2.2 Location

Location对象是浏览器提供的原生对象,提供URL相关的信息和操做方法。经过window.locationdocument.location属性,能够拿到这个对象。

对象属性

  • Location.href:整个 URL。若是对它写入新的 URL 地址,浏览器会马上跳转到这个新地址
  • Location.origin:URL 的协议、主机名和端口。
  • Location.protocol:当前URL的协议,包括冒号
  • Location.hostname:当前URL的主机(不包括端口)。而Location.host包括端口
  • Location.port:当前URL的端口号
  • Location.pathname:URL 的路径部分,从根路径/开始
  • Location.search:查询字符串部分,从问号?开始。

辅助方法

  • encodeURI()方法用于转码整个URL。它的参数是一个字符串,表明整个 URL。
  • decodeURI()方法用于整个URL的解码。它接受一个参数,就是转码后的URL。

3、存储对象

Cookie是服务器保存在浏览器的一小段文本信息,浏览器每次向服务器发出请求,就会自动附上这段信息。不一样浏览器对Cookie数量和大小的限制是不同的。通常来讲单个域名设置的 Cookie 不该超过30个,每一个Cookie的大小不能超过4KB。超过限制之后Cookie将被忽略,不会被设置。

Cookie 有一些主要用途:

  • 对话(session)管理:保存登陆、购物车等须要记录的信息。
  • 个性化信息:保存用户的偏好,好比网页的字体大小、背景色等等。

cookie的属性

cookie除了使用K-V形式设置Cookie的名字Cookie的值外,它还有如下属性:

  • Expires属性指定一个具体的到期时间,到了指定时间之后,浏览器就再也不保留这个Cookie。它的值是UTC格式,可使用Date.prototype.toUTCString()进行格式转换。若是不设置该属性或设为null,Cookie只在当前会话有效,浏览器窗口一旦关闭该Cookie就会被删除。
  • Max-Age属性指定从如今开始Cookie存在的秒数,好比60 * 60 * 24 * 365(即一年)。过了这个时间之后,浏览器就再也不保留这个 Cookie。若是同时指定了ExpiresMax-Age,那么Max-Age的值将优先生效。
  • Domain属性指定浏览器发出HTTP请求时,哪些域名要附带这个Cookie。若是没有指定该属性,浏览器会默认将其设为当前域名,这时子域名将不会附带这个Cookie。若是指定了该属性,那么子域名也会附带这个 Cookie。
  • Path属性指定浏览器发出HTTP请求时,哪些路径要附带这个Cookie。只要浏览器发现,Path属性是HTTP请求路径的开头一部分,就会在头信息里面带上这个Cookie。好比PATH属性是/,那么请求/docs路径也会包含它。
  • Secure属性指定浏览器只有在加密协议 HTTPS 下,才能将这个 Cookie 发送到服务器。
  • HttpOnly属性指定该Cookie没法经过JS脚本拿到,主要让document.cookieXMLHttpRequestRequest API拿不到该属性。这样就防止该Cookie被脚本读到。只有浏览器发出HTTP请求时,才会带上该Cookie。

cookie的交互

cookie的生成

在浏览器保存Cookie,就要在HTTP回应的头信息里面,放置一个或多个Set-Cookie字段。一个Set-Cookie字段可同时包括该cookie的多个属性,没有次序的要求。这个过程是服务端手动处理的。

Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly

cookie的发送

向浏览器发送Cookie,就要在HTTP回应的头信息里面,放置一个或多个Cookie字段。一个Cookie字段可同时包含多个 Cookie,使用分号分隔。这个过程是浏览器自动处理的。

Cookie: name=value; name2=value2; name3=value3

3.2 Storage

Storage接口用于脚本在浏览器保存数据,保存的数据都以“键值对”的形式存在。sessionStorage保存的数据用于浏览器的一次会话,当会话结束数据被清空;localStorage保存的数据长期存在,下一次访问该网站的时候,网页能够直接读取之前保存的数据。除了保存期限的长短不一样,这两个对象的其余方面都一致。目前每一个域名的存储上限视浏览器而定,Chrome是2.5MB,Firefox和Opera是5MB。

对象属性

  • StorageEvent.storageArea:返回键值对所在的整个对象。也就是说能够从这个属性上拿到当前域名储存的全部键值对。
  • StorageEvent.url:表示原始触发storage事件的那个网页的网址。
  • StorageEvent.key:表示发生变更的键名。若是storage事件是由clear()方法引发,该属性返回null
  • StorageEvent.newValue:表示新的键值。若是storage事件是由clear()方法引发,该属性返回null
  • StorageEvent.oldValue:表示旧的键值。若是该键值对是新增的,该属性返回null

对象方法

  • Storage.key()接受一个整数做为参数(从0开始),返回该位置对应的键值。
  • Storage.getItem()方法用于读取数据。它只有一个参数:键名。若是键名不存在,该方法返回null
  • Storage.setItem()方法用于存入数据。它接受两个参数:第一个是键名;第二个是保存的数据。若是键名已经存在,该方法会更新已有的键值。
  • Storage.removeItem()方法用于清除某个键名对应的键值。它接受键名做为参数,若是键名不存在,该方法不会作任何事情。
  • Storage.clear()方法用于清除全部保存的数据。

4、通讯对象

4.1 跨域通讯

所谓“同源”指的是“三个相同”:

  • 协议相同
  • 域名相同
  • 端口相同

常见的跨源通行方式有以下:

WebSocket

WebSocket是一种通讯协议,使用ws://(非加密)和wss://(加密)做为协议前缀。该协议不实行同源政策,只要服务器支持,就能够经过它进行跨源通讯。具体使用状况后续再补充。

JSONP

JSONP是服务器与客户端跨源通讯的经常使用方法。最大特色就是简单易用,老式浏览器所有支持,服务端改造很是小。去电就是JSONP只能发GET请求。

  • 第一步,网页添加一个<script>元素,向服务器请求一个脚本,这不受同源政策限制,能够跨域请求。

    <script src="http://api.foo.com?callback=bar"></script>

    注意请求的脚本网址有一个callback参数(?callback=bar),用来告诉服务器客户端的回调函数名称。

  • 第二步,服务器收到请求后,拼接一个字符串,将JSON数据放在函数名里面,做为字符串返回(bar({...}))。

  • 第三步,客户端会将服务器返回的字符串,做为代码解析。由于浏览器认为这是script标签请求的脚本内容。这时客户端只要定义了bar()函数,就能在该函数体内,拿到服务器返回的JSON数据。做为参数的JSON数据被视为 JavaScript对象而不是字符串,所以避免了使用JSON.parse的步骤。

function addScriptTag(src) {
  var script = document.createElement('script');
  script.setAttribute('type', 'text/javascript');
  script.src = src;
  document.body.appendChild(script);
}

window.onload = function () {
  addScriptTag('http://example.com/ip?callback=foo');
}

function foo(data) {
  console.log('Your public IP address is: ' + data.ip);
};

CORS

CORS是跨域资源分享(Cross-Origin Resource Sharing)的缩写。它是W3C标准,属于跨源AJAX请求的根本解决方法。它容许浏览器向跨域的服务器发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。相比JSONP只能发GET请求,CORS容许任何类型的请求。

CORS通讯与普通的AJAX通讯没有差异,代码彻底同样。浏览器一旦发现AJAX请求跨域,就会自动添加一些附加的头信息,有时还会多出一次附加的请求。所以实现 CORS 通讯的关键是服务器。只要服务器实现了CORS接口就可跨域通讯。

CORS 请求分红两类:简单请求和非简单请求。只要同时知足如下两大条件就属于简单请求,凡是不一样时知足上面两个条件就属于非简单请求。非简单请求是那种对服务器提出特殊要求的请求,好比请求方法是PUTDELETE,或者Content-Type字段的类型是application/json

  • 请求方法是如下三种方法之一:

    • HEAD
    • GET
    • POST
  • HTTP的头信息不超出如下几种字段:

    • Accept
    • Accept-Language
    • Content-Language
    • Last-Event-ID
    • Content-Type:只限于三个值application/x-www-form-urlencodedmultipart/form-datatext/plain

简单请求

简单请求发送:

对于简单请求,浏览器直接发出CORS请求。具体来讲就是在头信息之中,增长一个Origin字段。

GET /cors HTTP/1.1
Host: api.alice.com
Origin: http://api.bob.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...

简单请求响应:

服务器收到查询请求之后,检查了Origin字段之后,确认容许跨源请求就能够作出回应,返回的响应会多出几个头信息字段。若是服务器否认了查询请求,会返回一个正常的HTTP回应,可是没有任何CORS相关的头信息字段,或者明确表示请求不符合条件。浏览器发现这个回应的头信息没有包含Access-Control-Allow-Origin字段就知道出错了,从而抛出一个错误。该错误被XMLHttpRequestonerror回调函数捕获。注意这种错误没法经过状态码识别,由于HTTP回应的状态码有多是200。

Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: FooBar
Content-Type: text/html; charset=utf-8

上面的头信息之中,有三个与CORS请求相关的字段,都以Access-Control-开头:

  • Access-Control-Allow-Origin:该字段是必须的。它的值要么是请求时Origin字段的值,要么是一个*来表示接受任意域名的请求。注意若是服务器要求浏览器发送Cookie,该字段就不能设为星号,必须指定明确的、与请求网页一致的域名。
  • Access-Control-Allow-Credentials:该字段可选。表示是否容许发送Cookie。默认状况下,Cookie不包括在CORS请求之中。设为true即表示服务器明确许可,浏览器能够把Cookie包含在请求中,一块儿发给服务器。设为true同时要求开发者必须在AJAX请求中打开withCredentials属性,不然即便服务器要求发送 Cookie,浏览器也不会发送。
  • Access-Control-Expose-Headers:该字段可选。CORS请求时XMLHttpRequest对象的getResponseHeader()方法只能拿到服务器返回头的6个基本字段:Cache-ControlContent-LanguageContent-TypeExpiresLast-ModifiedPragma。若是想拿到其余字段,就必须在Access-Control-Expose-Headers里面指定。上面的例子指定getResponseHeader('FooBar')能够返回FooBar字段的值。

非简单请求

非简单请求发送:

非简单请求的CORS请求,会在正式通讯以前增长一次HTTP查询请求。浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可使用哪些HTTP方法和头信息字段。只有获得确定答复后浏览器才会发出正式的XMLHttpRequest请求,不然就报错。

这是为了防止这些新增的请求,对传统的没有CORS支持的服务器造成压力,给服务器一个提早拒绝的机会,这样能够防止服务器收到大量DELETEPUT请求,这些传统的表单不可能跨域发出的请求。

4.2 XMLHttpRequest

XMLHttpRequest对象是AJAX的主要接口,用于浏览器与服务器之间的通讯。尽管名字里面有XMLHttp,它实际上可使用多种协议(好比fileftp),发送任何格式的数据(包括字符串和二进制)。下面是XMLHttpRequest对象简单用法的完整例子:

var xhr = new XMLHttpRequest();

xhr.onreadystatechange = function(){
  // 通讯成功时,状态值为4
  if (xhr.readyState === 4){
    if (xhr.status === 200){
      console.log(xhr.responseText);
    } else {
      console.error(xhr.statusText);
    }
  }
};

xhr.onerror = function (e) {
  console.error(xhr.statusText);
};

xhr.open('GET', '/endpoint', true);
xhr.send(null);

对象属性

  • XMLHttpRequest.withCredentials属性是一个布尔值,表示跨域请求时用户信息(好比Cookie和认证的HTTP头信息)是否会包含在请求之中,默认为false,即向example.com发出跨域请求时,不会发送example.com设置在本机上的Cookie(若是有的话)。若是须要跨域AJAX请求发送Cookie,须要withCredentials属性设为true。注意同源的请求不须要设置这个属性。

  • XMLHttpRequest.upload属性返回一个对象,表示上传文件的相关事件。主要就是监听这个对象的各类事件。

  • XMLHttpRequest.timeout属性返回一个整数,表示多少毫秒后,若是请求仍然没有获得结果就会自动终止。若是该属性等于0,就表示没有时间限制。

  • XMLHttpRequest.readyState返回一个整数,表示实例对象的当前状态。它可能返回如下值:

    • 0,表示XMLHttpRequest实例已经生成,可是实例的open()方法尚未被调用。
    • 1,表示open()方法已经调用,可是实例的send()方法尚未调用,仍然可使用实例的setRequestHeader()方法,设定HTTP请求的头信息。
    • 2,表示实例的send()方法已经调用,而且服务器返回的头信息和状态码已经收到。
    • 3,表示正在接收服务器传来的数据体(body 部分)。这时若是实例的responseType属性等于text或者空字符串,responseText属性就会包含已经收到的部分信息。
    • 4,表示服务器返回的数据已经彻底接收,或者本次接收已经失败。
  • XMLHttpRequest.status属性返回一个整数,表示服务器回应的HTTP状态码。

  • XMLHttpRequest.responseType属性是一个字符串,表示服务器返回数据的类型。

  • XMLHttpRequest.response属性表示服务器返回的数据体(即HTTP回应的 body 部分),它多是任何数据类型(如字符串、对象、二进制对象等)。

  • XMLHttpRequest.responseURL属性是字符串,表示发送数据的服务器的网址。

  • XMLHttpRequest.responseText属性返回从服务器接收到的字符串。只有HTTP请求完成接收之后,该属性才会包含完整的数据。

对象事件

  • XMLHttpRequest.ontimeout:timeout事件的监听函数
  • XMLHttpRequest.onloadstart:loadstart事件(请求发出)的监听函数
  • XMLHttpRequest.onprogress:progress事件(正在发送和加载数据)的监听函数
  • XMLHttpRequest.onloadend:loadend 事件(请求完成,无论成功或失败)的监听函数
  • XMLHttpRequest.onabort:abort 事件(请求停止,如用户调用了abort()方法)的监听函数
  • XMLHttpRequest.onerror:error 事件(请求失败)的监听函数
  • XMLHttpRequest.onload:load事件(请求成功完成)的监听函数
  • XMLHttpRequest.onreadystatechange:readystatechange事件(实例的readyState属性变化)的监听函数

对象方法

  • XMLHttpRequest.open()方法用于指定HTTP请求的参数,或者说初始化XMLHttpRequest实例对象。注意若是对使用过open()方法的AJAX请求,再次使用这个方法,等同于调用abort(),即终止请求。
  • XMLHttpRequest.overrideMimeType()方法用来指定MIME类型,覆盖服务器返回的MIME类型,从而让浏览器进行不同的处理。好比服务器返回的数据类型是text/xml,因为种种缘由浏览器解析不成功报错,这时就拿不到数据。为了拿到原始数据能够把MIME类型改为text/plain,这样浏览器就不会去自动解析,从而可拿到原始文本。注意该方法必须在send()方法以前调用。
  • XMLHttpRequest.setRequestHeader()方法用于设置浏览器发送的HTTP请求的头信息。若是该方法屡次调用且设定同一个字段,则每一次调用的值会被合并成一个单一的值发送。注意该方法必须在send()方法以前调用。
  • XMLHttpRequest.getResponseHeader()方法返回HTTP头信息指定字段的值,若是尚未收到服务器回应或者指定字段不存在,则返回null
  • XMLHttpRequest.send()方法用于实际发出HTTP请求。
  • XMLHttpRequest.abort()方法用来终止已经发出的HTTP请求。调用这个方法之后,readyState属性变为4,status属性变为0。

至于其余的还有File对象、Blob对象、ArrayBuffer对象等,到时候随用随查吧。

相关文章
相关标签/搜索