浏览器原理笔记

浏览器原理笔记

1. 事件循环

1.1 为什么单线程却可以异步

事件循环,是浏览器或Node解决单线程运行时不会阻塞的一种机制。

JavaScript的确是一门单线程语言,但是浏览器UI是多线程的,异步任务借助浏览器的线程和JavaScript的执行机制实现。 例如,setTimeout就借助浏览器定时器触发线程的计时功能来实现。

1.2 事件循环的执行过程

  1. 代码开始执行,创建一个全局调用栈,script作为宏任务执行
  2. 执行过程过同步任务立即执行,异步任务根据异步任务类型分别注册到微任务队列和宏任务队列
  3. 同步任务执行完毕,查看微任务队列
    1. 若存在微任务,将微任务队列全部执行(包括执行微任务过程中产生的新微任务)
    2. 若无微任务,查看宏任务队列,执行第一个宏任务,宏任务执行完毕,查看微任务队列,重复上述操作,直至宏任务队列为空

1.3 微任务和宏任务的根本区别

  1. 微任务:指在当前任务执行结束后立即执行的任务,它可以看作是在当前任务的“尾巴”添加的任务。
    1. 常见的微任务包括:Promise、async/await
  2. 宏任务:指需要排队等待 JavaScript 引擎空闲时才能执行的任务。
    1. 常见的宏任务包括:setTimeout、setInterval、Ajax、DOM事件
  3. JavaScript 引擎会先执行当前任务中的所有微任务,然后再执行宏任务队列中的第一个任务。这个过程会不断重复,直到宏任务队列中的任务被全部执行完毕。

2. cookie和session的区别

2.1 存储位置不同

cookie的数据信息存放在本地。
session的数据信息存放在服务器上。

2.2 存储容量大小不同

cookie存储的容量较小,一般<=4KB。
session存储容量大小没有限制(但是为了服务器性能考虑,一般不能存放太多数据)。

2.3 存储有效期不同

cookie可以长期存储,只要不超过设置的过期时间,可以一直存储。
session在超过一定的操作时间(通常为30分钟)后会失效,但是当关闭浏览器时,为了保护用户信息,会自动调用session.invalidate()方法,该方法会清除掉session中的信息。

2.4 安全性不同

cookie存储在客户端,所以可以分析存放在本地的cookie并进行cookie欺骗,安全性较低。
session存储在服务器上,不存在敏感信息泄漏的风险,安全性较高。

2.5 域支持范围不同

cookie支持跨域名访问。例如,所有a.com的cookie在a.com下都能用。
session不支持跨域名访问。例如,www.a.com的session在api.a.com下不能用。

2.6 对服务器压力不同

cookie保存在客户端,不占用服务器资源。
session是保存在服务器端,每个用户都会产生一个session,session过多的时候会消耗服务器资源,所以大型网站会有专门的session服务器。

2.7 存储的数据类型不同

cookie中只能保管ASCII字符串,并需要通过编码方式存储为Unicode字符或者二进制数据。
session中能够存储任何类型的数据,包括且不限于string,integer,list,map等。

3. 哪些情况会造成内存泄漏

3.1 内存泄漏

内存泄漏(Memory Leak)是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。

3.2 意外的全局变量

在js中,一个未声明变量的使用,会在全局对象中创建一个新的变量;在浏览器环境下,全局对象就是window

1
2
3
4
5
6
7
function foo(){
a="test"
}
//上面的写法等同于
function foo(){
window.a ="test"
}

3.3 计时器和回调函数

定时器setInterval或者setTimeout在不需要使用的时候,没有被clear,导致定时器的回调函数及其内部依赖的变量都不能被回收,这就会造成内存泄漏。
解决方式:当不需要interval或者timeout的时候,调用clearInterval或者clearTimeout

3.4 脱离DOM的引用

获取一个DOM元素的引用, 而后面这个元素被删除了,由于一直保留了对这个元素的引用,所以它也无法被回收。

4. 对事件委托的理解

4.1 事件委托的概念

事件委托的本质是利用了浏览器事件冒泡的机制。在冒泡阶段,父节点可以通过事件对象获取到目标节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件,这种方式称为事件委托(事件代理)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<body>
<ul id="list">
<li id="item1">item1</li>
<li id="item2">item2</li>
<li id="item3">item3</li>
</ul>
<script>
document.getElementById("list").addEventListener("click", function (e) {
const target = e.target;
if (target.tagName === "LI" && target.parentNode === this)
console.log(target.innerHTML, '被点击');
})
</script>
</body>

4.2 事件委托的特点

减少内存消耗
如果有一个列表,列表中有大量的列表项,需要在点击列表项的时候响应一个事件。如果给每个列表项都绑定一个函数,对内存消耗非常大。可以把点击事件绑定到父节点上。
动态绑定事件
如果列表项存在频繁更新的情况,就需要每一次在改变的时候都重新给新增的元素绑定事件,给即将删除的元素解绑事件。如果使用事件委托就不需要这么麻烦,因为事件是绑定在父元素上的,和目标元素的增减无关。

4.3 局限性

focus、blur之类的事件没有冒泡机制,所以无法实现事件委托;mousemove、mouseout这样的事件,虽然有事件冒泡,但是只能不断通过位置去计算定位,对性能消耗高,因此不适合于事件委托。
事件委托也会影响页面性能,主要影响因素有:

  • 元素中,绑定事件委托的次数
  • 点击最底层元素,到绑定事件元素之间的DOM层数

5. XSS攻击

5.1 反射型XSS

5.2 存储型XSS

5.3 DOM型XSS

攻击示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<html>
<head>
<title>DOM Based XSS Demo</title>
<script>
function xsstest()
{
var str = document.getElementById("input").value;
document.getElementById("output").innerHTML = "<img
src='"+str+"'></img>";
}
</script>
</head>
<body>
<div id="output"></div>
<input type="text" id="input" size=50 value="" />
<input type="button" value="submit" onclick="xsstest()" />
</body>
</html>

在这段代码中,submit按钮的onclick事件调用了xsstest()函数。而在xsstest()中,修改了页面的DOM节点,通过innerHTML把一段用户数据当作HTML写入到页面中,造成了DOM Based XSS。

作者

zwx

发布于

2024-04-21

更新于

2024-04-21

许可协议

评论