1.事件轮询?
- JavaScript 是单线程的,同一时间只能做一件事。所有任务都需要排队,前一个任务结束,才会执行后一个任务,为了保证任务有序的执行,事件轮询就是单线程任务调度的一种方式,单线程任务分为同步任务和异步任务,而异步任务又分为宏任务和微任务
- 过程: 浏览器会首先执行宏任务, 如果执行过程中,遇到宏任务,就把他加入宏任务队列,遇到微任务,就把他加入微任务队列,当前宏任务执行完后,会判断 微任务列表 中是否有任务,如果有,执行微任务,当所有微任务执行完后,再执行下一个宏任务,不断循环。
- 宏任务:主代码块、setTimeOut、setInterval、script、I/O操作、UI渲染
- 微任务:promise、async/await(返回的也是一个promise)、process.nextTick
2.Hash和history的区别?
hash与history一般指前端框架中的路由模式,对应两种路由 hash路由和history路由
- hash路由兼容性比histroy路由好
- 浏览器url中hash 路由带了一个很丑的 #,而history是没有的
- hash即浏览器地址栏 URL 中的 # 符号,hash 虽然出现在 URL 中,但不会被包括在 HTTP 请求中,因此改变 hash 不会重新加载页面
- history利用了 HTML5新增的 pushState() 和 replaceState() 方法,在已有 back()、forward()、go() 的基础上,提供了对历史记录进行修改的功能。调用pushState() 和 replaceState()时,虽然改变了当前的 URL,但浏览器不会向后端发送请求,但如何用户刷新页面,会导致浏览器向服务器发起请求,如后端没有做出适当的响应,则会显示404页面
3.强缓存和协商缓存?
- 浏览器缓存主要分为强缓存(也称本地缓存)和协商缓存(也称弱缓存)。
- 浏览器在第一次请求发生后,再次发送请求时
- 强缓存:浏览器请求某一资源时,会先获取该资源缓存的header信息,然后根据header中的Cache-Control和Expires来判断是否过期。若没过期则直接从缓存中获取资源信息,包括缓存的header的信息,所以此次请求不会与服务器进行通信。这里判断是否过期,则是强缓存相关。
- 协商缓存:协商缓存就是由服务器来确定缓存资源是否可用,所以客户端与服务器端要通过某种标识来进行通信,从而让服务器判断请求资源是否可以缓存访问。主要看响应头的Etag和last-modify这两个字段.
- 强缓存状态码200,协商缓存304.
4.url过程?
- URL解析:当在浏览器地址栏输入URL后,浏览器会判断这个URL的合法性,以及是否有可用缓存。如果判断是URL则进行域名解析,如果不是URL,则直接使用搜索引擎搜索。
- 域名解析:浏览器首先会解析域名,获取对应的IP地址。这个过程涉及到了域名解析服务器的查询和转发,如果本地DNS缓存中有对应的条目,则可以直接使用缓存的IP地址。
- TCP连接:获取到IP地址后,浏览器便会与服务器建立TCP连接,包括客户端向服务器发送SYN(同步)报文,服务器回复SYN+ACK(同步/应答)报文,最后客户端再回复ACK(应答)报文,完成三次握手过程。
- 发送HTTP请求:TCP连接建立后,浏览器便会向服务器发送HTTP请求报文,其中包括请求方法、路径、协议版本等信息,以及请求头部信息等。
- 服务器响应:服务器接收到请求后,会从服务器文件系统或者处理逻辑中获取到数据,生成HTTP响应报文,并将其返回给浏览器。
- 浏览器渲染:当浏览器接收到响应报文后,会对HTML文档进行解析,并构建dom树、css树、渲染树等,最终将页面呈现给用户。
- 连接关闭:当浏览器从服务器接收到所有需要的数据后,就会关闭TCP连接。
5.浏览器渲染过程?
- 解析html,浏览器首先解析HTML文档,将其转化为dom树。这个过程中,浏览器会将HTML标签转化为节点,形成DOM树的结构。
- 解析CSS。浏览器解析CSS文件,构建css树。CSS树是包含所有CSS样式信息的树结构。
- 构建渲染树。将DOM树和CSSOM树合并,形成渲染树。渲染树只包含那些需要显示在页面上的元素,并且每个元素根据CSSOM包含了相应的样式信息。
- 布局计算。根据渲染树的结构,计算每个节点在屏幕上的大小、位置等属性,生成布局信息。这个过程涉及到元素的尺寸和位置的计算,可能会发生回流和重绘。
- 页面绘制。将生成的布局信息交给浏览器的绘图引擎,通过GPU加速将像素绘制到屏幕上。这一步将布局信息转化为实际的视觉展示。
- 执行JavaScript代码。浏览器的主线程负责解析和执行JavaScript代码。如果JavaScript代码修改了DOM,这可能会影响渲染树的构建和页面的绘制。
6.script脚本的异步加载顺序?
- script有两种异步加载方式 分别是defer与async
- defer与async的区别是:
- defer要等到整个页面在内存中正常渲染结束(DOM 结构完全生成,以及其他脚本执行完成),才会执行;
- async一旦下载完,渲染引擎就会中断渲染,执行这个脚本以后,再继续渲染。
- 一句话,defer是“渲染完再执行”,async是“下载完就执行”。
- 另外,如果有多个defer脚本,会按照它们在页面出现的顺序加载,而多个async脚本是不能保证加载顺序的。
7.ES6模块化和commonjs模块化区别?
- 语法不同:ES Module使用import导入,export或者export default导出,CommonJS使用require导入,exports导出
- 加载时机不同:ES Module是编译时加载,代码执行前,静态分析阶段,使用import函数时是运行时加载,CommonJS是运行时加载,必须等模块内所有代码运行结束后才能导出
- 加载方式不同:ES Module是异步加载,不会阻塞代码,CommonJS是同步加载,如果加载的模块够大时,可能会阻塞后续代码
- 导出方式不同:ES Module是导出值的引用,多个文件引入同一个模块得到的引用是同一个,CommonJS是值的拷贝
- 效率不同:ES Module加载效率更高,编译时加载、模块缓存机制、并行加载、tree-shaking,CommonJS效率相对较低
- 导出的内容不同:ES Module是编译阶段静态分析,导出静态定义,所以很多ES Module模块化的优化都是在这 个阶段做的,这也就是ES Module能够更好的支持tree shaking的原因,CommonJS导出的是对象,必须加载完模块内的所有代码才能生成导出对象,导致commonjs 不好优化
- ES Module导出的变量是只读的不能修改,修改了会报错,CommonJS导出的变量是可以修改的,这是因为ES Module导出的是引用,如果可修改会影响其他模块的导入,commonjs导出的是值的拷贝,不会影响
8.es6新特性?
- class 类
- let、const变量声明方式
- 新增了promise异步
- 新增了symbol基本数据类型
- 新增了proxy (代理)Api
- 新增了set、map数据结构
- es6模块化
- 新增了箭头函数
- 新增了模板字符串
- 新增了...扩展运算符
- 新增了生成器函数
- for...of循环
9.for....in.... 和 for....of.... 的区别?
- 遍历对象时:for…of 遍历获取的是对象的键值,for…in 获取的是对象的键名;
- 遍历数组时:for…of 只返回数组的下标对应的属性值,for…in 会返回数组中所有可枚举的属性(包括原型链上可枚举的属性),
- 总的来说for...in适合遍历对象,for...of适合遍历数组等可迭代的数据类型(数组、字符串等)
10.原型和原型链?
- 原型:构造函数的prototype属性,它的属性值是一个对象,这个对象包含了可以由该构造函数的所有实例共享的属性和方法。
- 原型链:当访问一个对象的属性时,如果这个对象内部不存在这个属性,那么它就会去它的原型对象里找这个属性,这个原型对象又会有自己的原型,于是就这样一直找下去,这种链状结构就叫做原型链