1.Webkit(Safari 内核)
浏览器内核可以分为四种:Trident(IE)、Gecko(火狐)、Blink(Chrome、Opera)、Webkit(Safari)
webkit的架构图
- 最底层是操作系统,WebKit 可以在不同的操作系统上工作
- 操作系统之上的就是 WebKit 依赖的第三方库,这些库是 WebKit 运行的基础
- 再往上一层就是 WebKit 项目了,图中又将其分为两层 WebCore JavaScriptCore WebKit Ports
WebCore
和WebKit Ports
之上的层主要提供嵌入式编程接口,提供给浏览器调用。接口层的定义也与移植密切相关,而不是 WebKit 有一个统一接口。WebKit2 嵌入式接口不是 WebKit 嵌入式接口的简单修改,而是为了浏览环境的安全性和稳定性原因考虑而引入了跨进程的架构。
其中,WebCore是Webkit的核心部分,它实现了对文档的模型化,包括了CSS, DOM, Render等的实现, JavaSript Core显然是对JavaSript支持的实现。WebKitPort方面的内容是可以很广的,例如可将不同的图形库、网络库与WebCore集成,提供不同的Port接口供外部程序使用等,例如同样在windows平台上可以运行的Google Chrome和Safari就是针对WebKit的不同移植。
2.内存泄漏处理
- 程序的运行需要内存。只要程序提出要求,操作系统或者运行时(runtime)就必须供给内存。
- 对于持续运行的服务进程(daemon),必须及时释放不再用到的内存。否则,内存占用越来越高,轻则影响系统性能,重则导致进程崩溃。
- 不再用到的内存,没有及时释放,就叫做内存泄漏(memory leak)。
常见的内存泄露
2.1 意外的全局变量:
由于 js 对未声明变量的处理方式是在全局对象上创建该变量的引用。如果在浏览器中,全局对象就是 window 对象。变量在窗口关闭或重新刷新页面之前都不会被释放,如果未声明的变量缓存大量的数据,就会导致内存泄露。
未声明变量
function fn() {
a = 'global variable'
}
fn()
使用 this 创建的变量(this 的指向是 window)。
function fn() {
this.a = 'global variable'
}
fn()
解决方法:
避免创建全局变量
使用严格模式,在 JavaScript 文件头部或者函数的顶部加上 use strict
。
2.2 闭包引起的内存泄漏:
原因:闭包可以读取函数内部的变量,然后让这些变量始终保存在内存中。如果在使用结束后没有将局部变量清除,就可能导致内存泄露。
function fn () {
var a = "I'm a";
return function () {
console.log(a);
};
}
解决:将事件处理函数定义在外部,解除闭包,或者在定义事件处理函数的外部函数中。
比如:在循环中的函数表达式,能复用最好放到循环外面。
// bad
for (var k = 0; k < 10; k++) {
var t = function (a) {
// 创建了10次 函数对象。
console.log(a)
}
t(k)
}
// good
function t(a) {
console.log(a)
}
for (var k = 0; k < 10; k++) {
t(k)
}
t = null
2.3 没有清理的 DOM 元素引用
原因:虽然别的地方删除了,但是对象中还存在对 dom 的引用。
// 在对象中引用DOM
var elements = {
btn: document.getElementById('btn'),
}
function doSomeThing() {
elements.btn.click()
}
function removeBtn() {
// 将body中的btn移除, 也就是移除 DOM树中的btn
document.body.removeChild(document.getElementById('button'))
// 但是此时全局变量elements还是保留了对btn的引用, btn还是存在于内存中,不能被GC回收
}
解决方法:手动删除,elements.btn = null
。
2.4 被遗忘的定时器或者回调
定时器中有 dom 的引用,即使 dom 删除了,但是定时器还在,所以内存中还是有这个 dom。
// 定时器
var serverData = loadData()
setInterval(function () {
var renderer = document.getElementById('renderer')
if (renderer) {
renderer.innerHTML = JSON.stringify(serverData)
}
}, 5000)
// 观察者模式
var btn = document.getElementById('btn')
function onClick(element) {
element.innerHTMl = "I'm innerHTML"
}
btn.addEventListener('click', onClick)
解决方法:手动删除定时器和 dom。
removeEventListener 移除事件监听
3. 页面加载和渲染
3.1 如何加载:
解析域名
你要访问一个网站,浏览器需要知道网站的IP地址,所以它向服务器发送一个包含域名的请求,然后DNS服务器返回对应的IP地址。
发起请求
浏览器向DNS查找到的那个IP地址的主机发起TCP连接,然后发送请求,请求中包含网址、浏览器信息、浏览器能接受的数据类型(也就是编码语言)、以及所有相关的cookies(存储在用户本地终端上的数据)(包含域和路径的cookies)
下载
浏览器会下载相关文件,浏览器解析html并识别出更多的资源,然后浏览器开始获取这些资源。
3.2 如何渲染
1)根据html文件构造DOM树,根据css文件构造CSSOM树。构建树期间,如果遇到JS,则阻塞DOM树和CSSOM树的构建,优先加载JS文件,加载完毕后再继续构建DOM树和CSSOM 树。(JS会对DOM节点进行操作,浏览器无法预测未来的DOM节点的具体内容,为了防止无效操作,节省资源,只能阻塞DOM树的构建。譬如,若不阻塞DOM树的构建,若JS删除了某个DOM节点A,那么浏览器为构建此节点A花费的资源就是无效的。)
HTML 文档中的所有内容皆是节点,各节点之间拥有层级关系,如父子关系、兄弟关系等,彼此相连,构成DOM树。
CSS文档中,所有元素皆是节点,与HTML文件中的标签节点一一对应。CSS中各节点之间同样拥有层级关系,如父子关系、兄弟关系等,彼此相连,构成CSSOM树。
为什么将CSS放在HTML前面?
让浏览器早点拿到CSS生成CSSOM,然后在解析HTML之后可一次性生成RenderTree,渲染一次就行了,如果放在HTML底部,会出现渲染卡顿的情况,影响性能和体验。
为什么要将JS放在HTML后面?
JS 放在底部可以保证让浏览器优先渲染完现有的 HTML 内容,让用户先看到内容,体验好。另外,JS 执行如果涉及 DOM 操作,得等待 DOM 解析完成才行,JS 放在底部执行时,HTML 肯定都解析成了 DOM 结构。JS 如果放在 HTML 顶部,JS 执行的时候 HTML 还没来得及转换为 DOM 结构,可能会报错。
2)将DOM和CSSSOM整合成RenderTree(渲染树)
渲染树(Render Tree)由DOM树、CSSOM树合并而成,但并不是必须等DOM树及CSSOM树加载完成后才开始合并构建渲染树。三者的构建并无先后条件,亦非完全独立,而是会有交叉,并行构建。因此会形成一边加载,一边解析,一边渲染的工作现象。
构建渲染树,根据渲染树计算每个可见元素的布局,并输出到绘制流程,将像素渲染到屏幕上。
3)页面的重绘和重排
重排必将引起重绘,而重绘不一定会引起重排。
重排,实际上是根据渲染树中每个渲染对象的信息,计算出各自渲染对象的几何信息(DOM对象的位置和尺寸大小),并将其安置在界面中的正确位置。重绘,就是当页面中元素样式的改变并不影响它在文档流中的位置时,例如更改了字体颜色,浏览器会将新样式赋予给元素并重新绘制的过程。
4. DOM-文档对象模型
document object model,一套操作页面元素的API。
DOM可以把HTML看做是文档树,通过DOM提供的API可以对树上的节点进行操作。
API(Application Programming Interface,应用程序编程接口)是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。
4.1 DOM的概念
文档对象模型(Document 0bject Model,简称 DOM),是 W3C组织推荐的处理可扩展标记语言的标准编程接口。它是一种与平台和语言无关的应用程序接口(API),它可以动态地访问程序和脚本,更新其内容、结构和 www文档的风格(目前,HTML 和XML文档是通过说明部分定义的)。文档可以进一步被处理,处理的结果可以加入到当前的页面。DOM是一种基于树的 API文档,它要求在处理过程中整个文档都表示在存储器中。
DOM树
创建新节点的方法
document.createElement("div") 创建元素节点
document.createAttribute(" id") 创建属性节点
document.createTextNode("hello") 创建文本节点
一般将创建的新节点存在变量中,方便使用。
DOM 经常进行的操作
·获取元素
·对元素进行操作(设置其属性或调用其方法)
·动态创建元素
·事件(什么时机做相应的操作)
4.2 获取页面元素
根据id 获取元素
·方法:调用document对象的 getElementByld方法。
根据标签名获取元素
·方法:调用document对象的 getElementsByTagName方法。
元素对象内部获取标签元素
·获取的元素对象内部,本身也可以调用根据标签获取元素方法,例如 div元素对象也可以调用getElementsByTagName方法。
根据 name 获取元素
·方法:调用document对象的getElementsByName方法。
根据类名获取元素
·方法:调用documert对象的 getElementsByClassName方法。
根据选择器获取元素
·方法1:调用document对象的querySelector方法,通过css 中的选择器去选取第一个符合条件的标签元素。
·方法2:调用document对象的querySelectorAll方法,通过css 中的选择器去选取所有符合条件的标签元素。
4.3 操作元素属性
非表单元素的属性
·例如: href、title、id、src等。
·调用方式:元素对象打点调用属性名,例如obj.href。
·注意:部分的属性名跟关键字和保留字冲突,会更换写法。
class → className
for → htmlFor
rowspan →rowSpan
·属性赋值:给元素属性赋值,等号右侧的赋值都是字符串格式。
获取标签内部内容的属性
获取标签内部内容的属性有两个:innerHTML和innerText
innerHTML属性,在获取标签内部内容时,如果包含标签,获取的内容会包含标签,获取的内容包括空白换行等。
innerText属性,在获取标签内部内容时,如果包含标签,获取的内容会过滤标签,获取的内容会去掉换行和缩进等空白。
表单元素属性
. value用于大部分表单元素的内容获取(option除外)
. type 可以获取input标签的类型(输入框或复选框等)- disabled禁用属性
. checked复选框选中属性. selected下拉菜单选中属性
·注意:在DOM中元素对象的属性值只有一个时,会被转成布尔值显示。
例如: txt.disabled = true;
自定义属性操作
getAttribute(name)获取标签行内属性
setAttribute(name,value)设置标签行内属性
removeAttribute(name)移除标签行内属性
与element.属性的区别:上述三个方法用于获取任意的行内属性,包括自定义的属性。
style样式属性操作
·使用style 属性方式设置的样式显示在标签行内。
. element.style属性的值,是所有行内样式组成的一个样式对象。
·样式对象可以继续点语法调用或更改css 的行内样式属性,例如 width、height等属性。
注意1:类似background-color这种复合属性的单一属性写法,是由多个单词组成的,要修改为驼峰命名方式书写backgroundColor。
·注意2:通过样式属性设置宽高、位置的属性类型是字符串,需要加上 px等单位。
className类名属性操作
·修改元素的className属性相当于直接修改标签的类名。
·如果需要修改多条css样式,可以提前将修改后的样式设置到一个类选择器中,后续通过修改类名的方式,批量修改css样式。
4.4 事件
·事件:在什么时候做什么事
·执行机制:触发--响应机制
·绑定事件(注册事件)三要素:
1、事件源:给谁绑定事件
2、事件类型:绑定什么类型的事件click单击
3、事件函数:事件发生后执行什么内容,写在函数内部
常用事件监听方法
方法1:绑定HTML元素属性。
·方法2:绑定DOM对象属性。
事件监听
·JavaScript解析器会给有绑定事件的元素添加一个监听,解析器会一直监测这个元素,只要触发对应的绑定事件,会立刻执行事件函数。
注册事件的其他方法
element.addEventListener()方法。
·参数:
第一个参数:事件类型的字符串(直接书写”click”,不需要加on)
第二个参数:事件函数
·同一个元素可以多次绑定事件监听,同一个事件类型可以注册多个事件函数
·兼容性问题:不支持 IE9 以下的浏览器
element.attachEvent()方法。
·参数:
第一个参数:事件类型的字符串(需要加on)
第二个参数:事件函数
·同一个元素可以多次绑定事件监听,同一个事件类型可以注册多个事件函数
·兼容性问题:只支持IE10及以下的浏览器
兼容写法:
<input type="button" value="点击" id="btn">
<script>
var btn = document.getElementById("btn");
//DOM 2级事件绑定方式
//参数:事件源,事件类型,事件函数
function addEvent(eLe,type,fn) {
// IE9及以上的浏览器和其他浏览器,使用addEventListener方法
//IE9以下的浏览器,使用attachEvent方法
if (ele.addEventListener) {
eLe.addEventListener(type,fn);
}else if (ele.attachEvent) {
ele.attachEvent("on"+ type,fn);
}
}
</script>
解除绑定方法:
btn.onclick = null;
element.removeEventListener()方法。
element.detachEventO方法。
4.5 事件流
事件流的三个阶段
·第一个阶段:事件捕获
·第二个阶段:事件执行过程
·第三个阶段:事件冒泡
addEventListener()第三个参数为false 时,事件冒泡
addEventListener()第三个参数为true时,事件捕获
onclick类型:只能进行事件冒泡过程,没有捕获阶段
attachEvent()方法:只能进行事件冒泡过程,没有捕获阶段
5. BOM
BOM 的概念
BOM (Browser 0bject Model)是指浏览器对象模型,浏览器对象模型提供了独立于内容的、可以与浏览器窗口进行互动的对象结构。BOM由多个对象组成,其中代表浏览器窗口的 Window对象是 BOM的顶层对象,其他对象都是该对象的子对象。
我们在浏览器中的一些操作都可以使用BOM的方式进行编程处理,比如:刷新浏览器、后退、前进、在浏览器中输入URL等。
window对象
window是浏览器的顶级对象,当调用window 下的属性和方法时,可以省略window。
注意: window下两个特殊的属性window. name、window.top,name只能传入字符串,top只读。
浏览器对象模型BOM中常用的对象有navigator,window, location, history。
5.1 Navigator对象
Navigator对象主要是用来帮助我们获取浏览器的一些信息的,例如浏览器的名称 、浏览器编译版本 、浏览器的语言 、浏览器使用的插件信息…… 并且该对象被所有支持javascript语言的浏览器支持,每个浏览器中的navigator对象都有一套自己的属性。
列举一些大多数浏览器都通用的Navigator对象的属性:
属性 | 描述 |
appName | 完整的浏览器名称 |
appVersion | 浏览器的版本 |
userAgent | 浏览器的用户代理字符串 |
platform | 浏览器所在的系统平台 |
cookieEnabled | 表示cookie是否被启用 |
plugins | 浏览器中所安装的插件信息数组 |
5.2 screen对象
该对象可以获取浏览器窗口外部显示器的信息,例如像素宽度和高度之类的。那因为每个浏览器的Screen对象都有他们各自支持和不支持的属性。
列举一下所有浏览器的支持的属性:
属性 | 描述 |
availHeight | 屏幕的像素高度减系统部件的高度之后的值(只读) |
availWidth | 屏幕的像素宽度减系统部件的宽度之后的值(只读) |
colorDepth | 用于表示颜色的位数(只读) |
height | 屏幕的像素高度 |
width | 屏幕的像素宽度 |
5.3 history对象
History 对象包含用户(在浏览器窗口中)访问过的 URL。
History 对象是 window 对象的一部分,可通过 window.history 属性对其进行访问。
注意: 没有应用于History对象的公开标准,不过所有浏览器都支持该对象。
History 对象属性
length 返回历史列表中的网址数
History 对象方法
back() | 加载 history 列表中的前一个 URL |
forward() | 加载 history 列表中的下一个 URL |
go() | 加载 history 列表中的某个具体页面 |
5.4 location对象
Location 对象包含有关当前 URL 的信息。
Location 对象是 window 对象的一部分,可通过 window.location.xxx 格式的相关属性对其进行访问。
注意: 没有应用于Location对象的公开标准,不过所有浏览器都支持该对象。
location对象属性
hash | 返回一个URL的锚部分 |
host | 返回一个URL的主机名和端口 |
hostname | 返回URL的主机名 |
href | 返回完整的URL |
pathname | 返回的URL路径名。 |
port | 返回一个URL服务器使用的端口号 |
protocol | 返回一个URL协议 |
search | 返回一个URL的查询部分 |
location对象方法
assign() | 载入一个新的文档 |
reload() | 重新载入当前文档 |
replace() | 用新的文档替换当前文档 |
6. h5存储
h5的浏览器存储有以下7种
1、cookie
这个存储用了很久了,而且也是以前大多网站十分喜欢的存储站点。但是也很容易被清除。同时cookie会在每一次通信过程中传向服务端。同时cookie有一个很好的地方就是,它本身有一个过期时间属性,可以用来标注一个变量的有效期。而cookie一旦过期就会被自动删除掉。
2、localStorage
localStorage: 持久存储,只要用户不主动删除就会一直存在。
3、sessionStorage
sessionStorage:面向session的浏览器存储,因此只存在于一个页面的生命周期内,关闭即清除两者均采用键值对的形式存储数据。
4、indexedDB
内嵌在浏览器端的非关系型数据库,数据以键值对的形式存储,兼容性良好indexDB直接操作的存储对象是ObjectStore,这有点类似其他数据库中table概念。
5、websql
内嵌在浏览器的关系型数据库,前端可以像在使用mysql、Oracle一样的写sql语句, 并存储信息。兼容性良好。存储后可在浏览器resource中查看。
6、window变量
生命周期有限,一般也不会去使用。但是对于全局变量的临时存储来说,还是一个不可多得的好地方。
7、flash cookie
flash cookie现在用的地方比较多。
FlashCookie是由FlashPlayer控制的客户端共享存储技术:
(1)类似HTTP Cookie,Flash Cookie利用 SharedObject类实现本地存储信息,SharedObject类用于在用户计算机上读取和存储有限的数据量,共享对象提供永久贮存在用户计算机上的对象之间的实时数据共享;
(2)本地共享对象是作为一些单独的文件来存储的,它们的文件扩展名为.SOL;
(3)本地共享对象并不是基于浏览器的,所以普通的用户不容易删除它们。如果要删掉它们的话,首先要知道这些文件所在的具体位置。这使得本地共享对象能够长时间的保留在本地系统上。
特点:比Cookie实现方式好,因为它无法通过浏览器快捷地删除,但比较专业的人士还是能通过本地查找删除:Flash Cookie文件存储在本地文件夹。
协商缓存
又称为对比缓存,客户端从缓存数据库中获取缓存数据的标识,然后向服务器发送请求,验证该数据是否失效,如果没失效,则服务器返回304,客户端从缓存数据库中读取数据,如果失效,则请求新的数据。
8. 调试
8.1 devtool的用处
- 前端开发:开发预览、远程调试、性能调优、
bug
跟踪、断点调试等 - 后端开发:网络抓包、开发调试Response
- 测试:服务端
API
数据是否正确、审查页面元素样式及布局、页面加载性能分析、自动化测试 - 其他:安装扩展插件,如
AdBlock、Gliffy、Axure
等
8.2 Charles 是在 PC 端常用的网络封包截取工具,在做移动开发时,我们为了调试与服务器端的网络通讯协议,常常需要截取网络封包来分析。除了在做移动开发中调试端口外,Charles 也可以用于分析第三方应用的通讯协议。配合 Charles 的 SSL 功能,Charles 还可以分析 Https 协议。
Charles 通过将自己设置成系统的网络访问代理服务器,使得所有的网络访问请求都通过它来完成,从而实现了网络封包的截取和分析。
Charles 主要的功能包括:
- 截取 Http 和 Https 网络封包。
- 支持重发网络请求,方便后端调试。
- 支持修改网络请求参数。
- 支持网络请求的截获并动态修改。
- 支持模拟慢速网络。
8.3 whistle是基于Node实现的跨平台web调试代理工具,同类型的工具有Fiddler和Charles,主要用于查看、修改HTTP、HTTPS、Websocket的请求、响应,也可以作为HTTP代理服务器使用。
在对比了Charles以及whistle之后,总结出来的whistle的优势有以下几点:
- 配置简单:whistle的配置类似于系统hosts的配置,一切操作都可以通过配置实现,支持域名、路径、正则表达式、通配符、通配路径等多种匹配方式。
- 支持扩展:whistle提供了插件扩展能力,通过插件可以新增whistle的协议实现更复杂的操作、也可以用来存储或监控指定请求、集成业务本地开发调试环境等等,基本上可以做任何你想做的事情,且开发、发布及安装whistle插件也都很简单。
- 内置weinre:通过weinre可以修改调试移动端DOM结构、捕获页面异常等。
- 界面简单易懂:从界面来看,whistle的功能划分为了network(网络)、rules(规则)、values(数据)、pulgins(插件)四大模块,通过tab页签进行切换。
- 文档全面:whistle官网提供了详细的说明文档,工作中遇到的情况只要查阅文档都能解决。