使用 MutationObserver 监视 DOM 变化
MutationObserver 可以用来监控 DOM 的变动。 这个 API 定义在 DOM4 中,被设计来替代已经废弃的 DOM3 事件:Mutation Events。
该 API 与事件不同的是,它并不会在每个 DOM 节点变化后立即执行回调函数,而是在 DOM 操作都完成后,将所有变化记录存储在数组中,在事件循环的 microtask 阶段执行回调函数,一次性处理这些存储的变化。
注: 一次事件循环,从 macrotask quene 中取出一个任务执行,执行完毕后,执行整个 microtask quene 中的任务。
构造函数:
MutationObserver(callback)callback 在每个 DOM 变动中被调用,这个回调函数接受两个参数:
- mutationRecords 改变记录列表
- observer 即 MutationObserver 实例
JavaScript 闭包
闭包(词法闭包)的定义
闭包是「函数」以及该函数相关的「引用环境」组合而成的实体。
这个定义中,包含了两个核心的要素:
- 函数:一段可以执行的代码
- 引用环境:生成闭包时的词法环境
观察以下这段 JavaScript 代码:
function outer() { var _private = 'private'
return function inner() { return _private }}
var getPrivate = outer()console.log(getPrivate.name) // 'inner'getPrivate() // 'private'函数 outer 调用后,会将在其内部定义的函数 inner 暴露出来并赋值给 getPrivate,在下一行代码可以确认这点。
再继续下一行,我们调用 getPrivate,发现成功得到了 outer 的本地变量 _private,尽管此时 outer 已经返回(我们学习过的编程知识告诉我们,函数执行时在栈上分配的变量会在离开函数执行环境时被销毁)。这个例子的实际结果说明 outer 的本地变量 _private 被保存在某个地方(堆上分配)继续可用。
根据这些表现,我们可以确认这就是一个典型的闭包。
实际上,这个闭包在 outer 被调用的时候创建。它在某个地方保存了函数 inner 所需要的引用环境,使得离开了创建闭包的环境(outer)时,对自由变量的引用依旧有效(直至闭包的生命周期结束才一并被回收)。
READ MORE...注:自由变量是指在函数之外的定义的变量,它既不是本地变量,也不是参数。
DOM (Level 2) 事件流
闲暇无事复习下 DOM 事件流,顺便做做笔记记录一些重点。
先看一段简单的 HTML 代码:
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Document</title></head><body> <div id="div"></div></body></html>我们在点击 div 的时候,而事件流是这样传播的:
1. 捕获阶段
最先开始的是捕获阶段。
按照 DOM Level 2 标准要求,事件会从 document 开始向内部传播,途径 html、body,最终在事件目标 (event target) div 之前停止。从而有机会在事件流到达目标之前捕获。
然而实际上是这样的:
- IE9, Safari, Chrome, Opera, Firefox 会从
window开始捕获事件。 - IE9,Safari,Chrome,Firefox,Opera 9.5+ 等浏览器,捕获阶段不会在事件目标前停止,会继续传播到事件目标。
JavaScript 中的多行文本
有时候,我们需要使用 JavaScript 构造一些 HTML 代码,如下:
<div id="outer"> <div id="inner"> 内容 </div></div>用 JavaScript 字符串来表示就是:
const html = '<div id="outer"><div id="inner">内容</div></div>'为了可读性和避免写错,就有强烈的写成带缩进的多行文本的需求。 现阶段,JavaScript 的多行文本,大家马上能想到的就是用 ES6 的字符串模板字面量来创建。
const html = `<div id="outer"> <div id="inner"> 内容 </div></div>`忆苦思甜,以前都是怎么做的呢?
可能大家还有印象,最笨拙的字符串拼接方法:
var html = ''+ '<div id="outer">'+ '<div id="inner">'+ '内容'+ '</div>'+ '</div>'还有利用反斜杠的方式:
var html = '\<div id="outer">\ <div id="inner">\ 内容\ </div>\</div>\'利用数组的方式:
var html = ['<div id="outer">',' <div>',' 内容',' </div>','</div>'].join('')不走寻常路的利用读取函数内容的方式:
function hereDoc(docFn) { return docFn.toString().replace(/^[^\/]+\/\*!?\s?/, '').replace(/\*\/[^\/]+$/, '')}
var html = hereDoc(function(){/*!<div id="outer"> <div id="inner"> 内容 </div></div>*/})在浏览器环境中,也可以直接在 HTML 中写模板代码,然后 JavaScript 读取内容:
<script id="template" type="text/template"> <div id="outer"> <div id="inner"> 内容 </div> </div></script>var html = document.getElementById('template').textContent讲了这么多种书写多行字符串的方法,有什么用处呢?
其实什么用都没,大部分场景,无脑使用 ES6 的模板字面量即可。
全文完
READ MORE...TCP 协议知识整理
TCP
TCP (Transmission Control Protocol) 是一种传输层通信协议。
在因特网协议族(Internet protocol suite)中,TCP层是位于IP层之上,应用层之下的中间层。
不同主机的应用层之间经常需要可靠的、像管道一样的连接,但是IP层不提供这样的流机制,而是提供不可靠的包交换。
TCP 传输过程
一个典型的传输过程,就是一个对数据的逐层封装:
-
一、应用层向传输层发送用于网间传输的、用8位字节表示的数据流(Stream)。
|:------:| | 用户数据 |
-
二、传输层的 TCP 把数据流分割成适当长度(受所处网络的数据链路层 MTU 限制)的报文段(segment)。
|:------:|:------:| | TCP 头 | 用户数据 |
-
三、TCP 把结果传给网络层。网络层的 IP 将报文段封装成数据报(Datagram)。
|:-----:|:-----:|:-------:| | IP 头 | TCP 头 | 用户数据 |
-
四、IP 层再将数据报交由数据链路层封装成帧(Frame)用于发送。
|:---:|:-----:|:------:|:------:|:----:| | 帧头 | IP 头 | TCP 头 | 用户数据 | 帧尾 |
-
五、通过物理层传输数据。
接受端对数据的操作是个反向操作,称为解封装,逐层移除头信息。
TCP 连接创建(三次握手 three-way handshake)
建立一个 TCP 连接,需要经过三次握手:
READ MORE...