怎样添加, 移除, 复制, 创建, 查找节点
创建节点
- document.createDocumentFragment(); // 创建一个空的虚拟节点, 一个 DOM 片段
- document.createEelement(TagName); // 创建指定的 DOM 节点
- document.createTextNode(); // 创建一个文本节点
- document.createAttribute(); // 创建一个属性节点
- document.createComment(); // 创建一个注释节点
删除 (移除) 节点
- parentNode.removeChild('需要删除的子节点'); // 删除, 利用父元素节点删除子节点
- element.remove(); // 删除自身, 兼容性不好
添加节点
- parentNode.appendChild('子节点'); // 给父元素节点添加子节点
- parentNode.append('节点','节点','节点','...'); // 添加子节点, 参数可以是多个节点, 兼容性不好
- parentNode.insertBefore('新节点', '旧节点'); // 将一个新节点插入到一个旧节点之前.
替换节点
parentNode.replaceChild('新节点', '旧节点'); // 调用父节点的方法, 用一个新节点替换掉一个旧节点
复制节点
- element.cloneNode('布尔值');
- // 克隆节点. 如果参数为 true 的话, 会递归复制当前元素的所有子孙节点. 否则的话只复制当前节点本身.
查找节点
通过 document 查找.
- document.getElementById(); // 通过 ID 查找 DOM 元素;
- document.getElementsByTagName(); // 通过标签选择器查找 DOM 元素; 可以是 '*', 返回当前所有的 DOM 节点.
- document.getElementsByClassName(); // 通过 class 类名查找 DOM 元素; 返回一个 NodeList 伪数组.
- document.getElementsByName(); // 通过 name 属性查找 DOM 元素; 返回所有 name 符合的元素.
- document.querySelector(); // html5 新增, 通过 CSS 选择器选择元素, 返回匹配的第一个元素.
- document.querySelectorAll(); // HTML5 新增, 通过 CSS 选择器选择元素, 返回匹配的所有元素组成的 NodeList.
- document.forms; // 返回当前文档中的所有 form 表单.
- document.images; // 返回当前文档中的所有 img 图片.
- document.scripts; // 返回当前文档中所有的 script 脚本.
- document.activeElement; // 返回当前获取焦点的节点.
- document.documentElement; // 返回当前文档的根节点.
- document.body; // 返回当前文档的 body 节点.
通过 element 查找.
- element.childNodes; // 返回当前节点的所有子节点(包括文本节点和空白节点).
- element.children; // 返回当前节点的所有子元素节点.
- element.firstChild; // 返回当前节点的第一个子节点(包括空白节点, 文本节点).
- element.firstElementChild; // 返回当前节点的第一个元素节点.
- element.lastChild; // 返回当前元素的最后一个子节点(包括空白节点, 文本节点).
- element.lastElementChild; // 返回当前节点的最后一个元素节点.
- element.nextSibling; // 返回当前节点的下一个兄弟节点(包括空白节点, 文本节点).
- element.nextElementSibling; // 返回当前节点的下一个兄弟元素节点.
- element.previousSibling; // 返回当前节点的上一个兄弟节点(包括空白节点, 文本节点).
- element.previousElementSibling; // 返回当前节点的上一个兄弟元素节点.
- element.parentNode; // 返回当前节点的父节点.
- element.parentElement; // 返回当前节点的父元素节点. // IE9 以下不兼容.
jQuery 的事件委托 on,live,delegate 之间有什么区别
live
定义和用法: 主要用于给选择到的元素上绑定特定事件类型的监听函数;
语法: live(type, [data], fn);
特点:
live 方法并没有将监听器绑定到自己 (this) 身上, 而是绑定到了 this.context 上了.
live 正是利用了事件委托机制来完成事件的监听处理, 把节点的处理委托给了 document, 新添加的元素不必再绑定一次监听器.
使用 live()方法但却只能放在直接选择的元素后面, 不能在层级比较深, 连缀的 DOM 遍历方法后面使用, 即("ul").live... 可以, 但("ul").live... 可以, 但("body").find("ul").live... 不行;
delegate
定义和用法: 将监听事件绑定在就近的父级元素上;
语法: delegate(selector,type,[data],fn)
特点:
选择就近的父级元素, 因为事件可以更快的冒泡上去, 能够在第一时间进行处理.
更精确的小范围使用事件代理, 性能优于. live(). 可以用在动态添加的元素上.
on
定义和用法: 将监听事件绑定到指定元素上.
语法: on(type,[selector],[data],fn)
参数的位置写法与 delegate 不一样.
说明: on 方法是当前 jQuery 推荐使用的事件绑定方法, 附加只运行一次就删除函数的方法是 one().
它们三个之间的区别
live 把事件委托交给了 document(根节点),document 向下去寻找符合条件的元素, 不用等待 document 加载结束也可以生效.
delegate 可指定事件委托对象, 相比于 live 性能更优, 直接锁定指定选择器;
on 事件委托对象选填, 如果不填, 即给对象自身注册事件, 填了作用和 delegate 一致.
原生 JS 面试题 - 刘悦 Lau
描述一次完整的 http 请求过程(输入 url 敲回车发生了什么)
当我们开始在浏览器中输入网址的时候, 浏览器其实就已经在智能的匹配可能得 url 了, 他会从历史记录, 书签等地方, 找到已经输入的字符串可能对应的 url, 然后给出智能提示, 让你可以补全 url 地址
浏览器查找域名的 IP 地址. 请求一旦发起, 浏览器首先要做的事情就是解析这个域名, 一般来说, 浏览器会首先查看本地硬盘的 hosts 文件, 看看其中有没有和这个域名对应的规则, 如果有的话就直接使用 hosts 文件里面的 ip 地址. 如果在本地的 hosts 文件没有能够找到对应的 ip 地址, 浏览器会发出一个 DNS(因特网上作为域名和 IP 地址相互映射的一个分布式数据库, 能够使用户更方便的访问互联网, 而不用去记住能够被机器直接读取的 IP 数串. 通过主机名, 最终得到该主机名对应的 IP 地址的过程叫做域名解析 (或主机名解析)) 请求到本地 DNS 服务器 . 本地 DNS 服务器一般都是你的网络接入服务器商提供, 比如中国电信, 中国移动. 查询你输入的网址的 DNS 请求到达本地 DNS 服务器之后, 本地 DNS 服务器会首先查询它的缓存记录, 如果缓存中有此条记录, 就可以直接返回结果, 此过程是递归的方式进行查询. 如果没有, 本地 DNS 服务器还要向 DNS 根服务器进行查询. 本地 DNS 服务器继续向域服务器发出请求, 在这个例子中, 请求的对象是. com 域服务器..com 域服务器收到请求之后, 也不会直接返回域名和 IP 地址的对应关系, 而是告诉本地 DNS 服务器, 你的域名的解析服务器的地址. 最后, 本地 DNS 服务器向域名的解析服务器发出请求, 这时就能收到一个域名和 IP 地址对应关系, 本地 DNS 服务器不仅要把 IP 地址返回给用户电脑, 还要把这个对应关系保存在缓存中, 以备下次别的用户查询时, 可以直接返回结果, 加快网络访问.
image
浏览器向 web 服务器发送一个 HTTP 请求. 在通过 DNS 域名解析后, 获取到了服务器的 IP 地址, 在获取到 IP 地址后, 便会开始建立一次连接, 这是由 TCP 协议完成的, 主要通过三次握手进行连接:
第一次握手: 建立连接时, 客户端发送 syn 包 (syn=j) 到服务器, 并进入 SYN_SENT 状态, 等待服务器确认;
第二次握手: 服务器收到 syn 包, 必须确认客户的 SYN(ack=j+1), 同时自己也发送一个 SYN 包(syn=k), 即 SYN+ACK 包, 此时服务器进入 SYN_RECV 状态;
第三次握手: 客户端收到服务器的 SYN+ACK 包, 向服务器发送确认包 ACK(ack=k+1), 此包发送完毕, 客户端和服务器进入 ESTABLISHED(TCP 连接成功)状态, 完成三次握手.
image
浏览器向服务器发送 HTTP 请求
服务器返回一个 HTTP 响应, 浏览器接收响应
服务器在收到浏览器发送的 HTTP 请求之后, 会将收到的 HTTP 报文封装成 HTTP 的 Request 对象, 并通过不同的 Web 服务器进行处理, 处理完的结果以 HTTP 的 Response 对象返回, 主要包括状态码, 响应头, 响应报文三个部分.
状态码主要包括以下部分
1xx: 指示信息 - 表示请求已接收, 继续处理.
2xx: 成功 - 表示请求已被成功接收, 理解, 接受.
3xx: 重定向 - 要完成请求必须进行更进一步的操作.
4xx: 客户端错误 - 请求有语法错误或请求无法实现.
5xx: 服务器端错误 - 服务器未能实现合法的请求.
响应头主要由 Cache-Control, Connection,Date,Pragma 等组成.
响应体为服务器返回给浏览器的信息, 主要由 HTML,CSS,JS, 图片文件组成.
页面渲染. 如果说响应的内容是 HTML 文档的话, 就需要浏览器进行解析渲染呈现给用户. 整个过程涉及两个方面: 解析和渲染. 在渲染页面之前, 需要构建 DOM 树和 CSSOM 树.
image
image
在浏览器还没接收到完整的 HTML 文件时, 它就开始渲染页面了, 在遇到外部链入的脚本标签或样式标签或图片时, 会再次发送 HTTP 请求重复上述的步骤. 在收到 CSS 文件后会对已经渲染的页面重新渲染, 加入它们应有的样式, 图片文件加载完立刻显示在相应位置. 在这一过程中可能会触发页面的重绘或重排. 这里就涉及了两个重要概念: Reflow 和 Repaint.
Reflow, 也称作 Layout, 中文叫回流, 一般意味着元素的内容, 结构, 位置或尺寸发生了变化, 需要重新计算样式和渲染树, 这个过程称为 Reflow.
Repaint, 中文重绘, 意味着元素发生的改变只是影响了元素的一些外观之类的时候(例如, 背景色, 边框颜色, 文字颜色等), 此时只需要应用新样式绘制这个元素就 OK 了, 这个过程称为 Repaint.
所以说 Reflow 的成本比 Repaint 的成本高得多的多. DOM 树里的每个结点都会有 reflow 方法, 一个结点的 reflow 很有可能导致子结点, 甚至父点以及同级结点的 reflow.
下面这些动作有很大可能会是成本比较高的:
1. 增加, 删除, 修改 DOM 结点时, 会导致 Reflow 或 Repaint
2. 移动 DOM 的位置, 或是搞个动画的时候
3. 内容发生变化
4. 修改 CSS 样式的时候
5. Resize 窗口的时候(移动端没有这个问题), 或是滚动的时候
6. 修改网页的默认字体时
基本上来说, reflow 有如下的几个原因:
1. Initial, 网页初始化的时候
2. Incremental, 一些 JS 在操作 DOM 树时
3. Resize, 其些元件的尺寸变了
4. StyleChange, 如果 CSS 的属性发生变化了
5. Dirty, 几个 Incremental 的 reflow 发生在同一个 frame 的子树上
关闭 TCP 连接或继续保持连接
通过四次挥手关闭连接(FIN ACK, ACK, FIN ACK, ACK).
image
第一次挥手是浏览器发完数据后, 发送 FIN 请求断开连接.
第二次挥手是服务器发送 ACK 表示同意, 如果在这一次服务器也发送 FIN 请求断开连接似乎也没有不妥, 但考虑到服务器可能还有数据要发送, 所以服务器发送 FIN 应该放在第三次挥手中.
这样浏览器需要返回 ACK 表示同意, 也就是第四次挥手.
至此从浏览器地址栏输入 URL 到页面呈现到你面前的整个过程就分析完了!!!
本题原文链接: 从输入 url 到页面展示到底发生了什么 @小四 -- 王云飞_小四_wyunfei
如果本文对您有帮助, 可以看看本人的其他文章:
原生 JS - 瀑布流布局 @郝晨光
原生 JS - 图片懒加载 @郝晨光
Koa - Node.JS 框架学习 @郝晨光
结言
感谢您的查阅, 本文由郝晨光整理并总结, 代码冗余或者有错误的地方望不吝赐教; 菜鸟一枚, 请多关照
来源: http://www.jianshu.com/p/f91ad3ad97f4