执行上下文
代码在执行期间运行的环境。存储变量和函数的地方,决定了变量和函数的可访问性。分为全局执行上下文[在代码被执行之前创建,全局变量和函数都在这里],函数执行上下文[函数被调用时会创建一个新的函数上下文,每个函数都有自己的独立上下文,包含函数的参数,局部变量和内部函数],eval[eval函数执行上下文]
在 JavaScript 中,执行上下文是栈形式的数据结构,它用来管理和控制代码的执行流程。当代码执行到一个函数时,会创建一个函数执行上下文并将其推入栈中,当函数执行完毕后,其上下文会从栈中弹出。
作用域和作用域链
作用域是变量可以使用的范围,分为全局作用域和局部作用句(函数作用域和块级作用域[es6])。是变量起作用的范围,定义的时候就已经确定了[静态作用域/词法作用域]。作用域链就是在作用域嵌套下,由内向外,层层访问形成的链式规则。
原型和原型链
每个函数都有的prototype属性叫原型,它是一个对象。每个对象都有一个__proto__属性,指向它构造函数的原型对象。
假设存在一个构造函数Person,只要是函数就存在一个prototype属性叫原型,可以把一些共享的属性和方法挂载到它身上。通过new Person创建一个person的实例对象,它其中就存在了一个__proto__隐式原型指向它构造函数的显示原型。在对对象的属性进行查找的时候,会在他自己对象上查找,然后到它构造函数的原型上查找。如果在构造函数的原型上也找不到,因为这个prototype也是一个对象也有一个__proto__对象指向它的父级的构造函数就会在它的父级的原型上查找,最后找到null,在查找的过程中就形成了一条链,就是原型链。
闭包
一个能访问外部作用域变量的函数。
通常以函数嵌套的方式存在,即一个函数嵌套另一个函数,函数内部能访问到函数外部的变量,这就形成了闭包。
闭包可以在私有化变量的基础上保持数据。
防抖节流函数就应用到了数据保持这个特性。
在防抖函数中,对按钮进行点击的时候,会定义一个time定时器。如果不采用闭包,那么下一次点击的时候会重新生成一个新的定时器,两个定时器的引用不同,是没有关联的。使用闭包的话我们可以在内存中直接找到之前创建的定时器,调用就可以拿到对应定时器的时间进行操作。
闭包容易造成内存泄漏,所以在最后要对定时器进行及时的清空。
// 防抖函数
// 将多次触发的函数合并成一次触发
function debounce(fn, delay){
let time = null;
return function(){
if(timer) {
clearTimeout(timer);
}
timer = setTimeout(() => {
fn.call(this, arguments);
timer = null;
}, delay)
}
}
浏览器输入到页面渲染的流程
DNS解析 → TCP连接 → 发送请求 → 服务器处理请求 → 发送响应 → 接受响应 → 解析文档 → 加载资源 → 渲染页面 → 执行javascript → 加载完成
浏览器接收url并开启一个新进程(这一部分可以展开浏览器的进程与线程的关系) 浏览器解析输入的 URL,提取出其中的协议、域名和路径等信息。(这部分涉及URL组成部分)
浏览器向 DNS 服务器发送请求,DNS服务器通过 多层查询 将该 域名 解析为对应的 IP地址 ,然后将请求发送到该IP地址上,与 服务器 建立连接和交换数据。(这部分涉及DNS查询)
浏览器与服务器建立 TCP 连接。(这部分涉及TCP三次握手/四次挥手/5层网络协议) 浏览器向服务器发送 HTTP 请求,包含请求头和请求体。(4,5,6,7包含http头部、响应码、报文结构、cookie等知识)
服务器接收并处理请求,并返回响应数据,包含状态码、响应头和响应体。
浏览器接收到响应数据,解析响应头和响应体,并根据状态码判断是否成功。
如果响应成功,浏览器接收到http数据包后的解析流程(这部分涉及到html - 词法分析,解析成DOM树,解析CSS生成CSSOM树(样式树),合并生成render渲染树(样式计算)。然后layout布局,分层,调用GPU绘制等,最后将绘制的结果合成最终的页面图像,显示在屏幕上。这个过程会发生回流和重绘)。
连接结束 -> 断开TCP连接 四次挥手
浏览器页面加载机制
解析html构建DOM树,解析CSS构建CSS树,合并DOM树和CSS树生成渲染树。布局render tree进行布局计算。执行javascript代码更新DOM tree 和CSS tree。重绘和回流。