You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
为了保证http不受影响,那就需要在应用层(HTTP2.0)和传输层(TCP or UDP)之间增加一个二进制分帧层。在二进制分帧层上,http2.0会将所有传输的信息分为更小的消息和帧,并采用二进制格式编码,其中http1.x的首部信息会被封装到Headers帧,而Request Body则封装到Data帧。在传输中会共用一个TCP流(TCP连接中的一个虚拟通道,可以承载双向的消息),不至于重复连接。
方便访问:语雀博文原文地址
这次对前端技术涉及到的点进行了一次有序的整理,这样记得更牢,也希望可以帮助到大家,下面是目录结构。(其中有很多内容被简化了,有兴趣可以查看每个目录下的参考文档,内容相对更加详情)
Js基础
javaScript数据类型5+1
基本类型 ——
number
、string
、undefind
、boolean
、null
;引用类型——
Object
;目前基本类型中添加了一个新成员:
symbol
;基本类型和引用类型区别:前者按值访问,因此为我们操作的就是存储在变量中的实际值;后者不能直接操作对象所在的内存空间,在操作对象时,实际操作的是该对象的引用。
基本类型存储在
栈
中;引用类型的 ‘变量’名称 存储在栈
中,同时存储指针,该指针指向堆
中的真实的值;(栈
、堆
概念可以直接搜索 "js中栈和堆的概念和区别")参考书:犀牛书
this指向
箭头函数:this继承包裹箭头函数的第一个普通函数中的this;
普通函数:new(this指向新对象)——bind/apply/call(this是强制指向的this)——this指向函数上下文对象——this指向window;
参考文章:https://juejin.cn/post/6844903941021384711
参考书:红宝书
闭包
一个函数引用另外一个函数内部变量就会形成闭包,闭包在平时开发中非常的多见;理解作用域链创建和使用的细节对理解闭包非常重要;
参考文章:https://juejin.cn/post/6844903747957719053
参考书:红宝书
原型
每个对象被创建开始,就与另一个对象关联,从另一个对象上继承其属性,这里的另一个对象就是原型;
原型存在的意义就是组成原型链。当范文一个对象属性时,先从对象本身找,找不到就去对象原型上找,如果还找不到,就去对象原型的原型上找,如此类推,直到找到为止;这条由对象及原型组成的查找链条就是原型链;
参考文章:https://juejin.cn/post/6844903936365690894
参考书:红宝书
继承
组合继承:通过
call
修改子类this
,将子类原型指向new 父类()
;寄生组合继承:通过
call
修改子类this
,将子类原型指向父类原型(Object.create(父类.prototype)) ,并将子类原型构造函数指向子类;参考书:红宝书
模块化
模块化特点:复用性、可维护性;
commonJs
最早作为标准在NodeJs中引入, 作为NodeJs模块化标准;在commonJs
中,require
首次加载就会执行整个脚本,在内存中生成一个对象缓存下来,下次加载时可直接从缓存获取;对于循环加载,只输出已执行的部分。还未执行部分不输出;
最新ES6的 ES Module,是静态加载;脚本被加载时,成为一个指向被加载模块的引用,不会缓存;
并发和并行
区别:并发是两个或多个事件在同一时间间隔内发生;并行是指两个或多个事件在同一时刻内发生;
并行通过提升硬件能力,只需要多核CPU即可达到;
并发中最常听到的就是高并发,在一定时间,服务器的吞吐量和QPS每秒响应请求数都是一定的。而在这样的情况下,要解决高并发的问题,最简单当然是提升机器性能,加内存,加硬盘,升级网速。当然,通过架构层面设计,也可以做点东西,部署多台机器,添加负载均衡层,将请求均匀;将数据库分库分表并读写分离;引入消息中间件等;缓存集群引入;
异步方案
回调函数:在浏览器端,异步问题就是Ajax网络请求响应异步,而回调函数可以一定程度解决这个响应异步的问题,缺点是:不易维护、不易读、不能直接return;
Generator:封装多个内部状态的异步解决方案,生成器函数;会返回一个迭代器,配合next()函数,可以控制开始、暂停和恢复代码;
场景:控制流管理、异步操作;
Promise:解决异步操作方案,包含异步操作结果的对象;内部存在三种状态,一旦开始不可更改状态;问题:无法取消,错误需要回调捕获;Promise是链式调用,每次调用then之后返回一个Promise,并且是一个全新的Promise;
Promise实现依据Promise/A+规范——
三种状态:pedding、fulfilled、rejected;
(Promise封装的Ajax为例子)进行异步处理流:执行Promise回调函数,由于异步操作,内部状态未变化。继续执行then回调,内部状态未变化,回调队列中then回调暂时不执行。此时,异步执行完成(网络请求响应),状态变化,Promise内部调用resolve函数,回调队列执行;
async/await:异步解决方案,需要配套使用;函数添加async后,函数会返回一个Promise;await内部实现了Generator,await是异步操作,后来的表达式不返回Promise的话,就会包装成Promise.resolve(返回值 ),然后去执行函数外的同步代码;
事件循环
1. js的事件循环如何环执行?
浏览器事件循环执行顺序:
2. 宏任务和微任务有哪些?
宏任务:script、setTimeout、setInterval、setImmediate、I/O、UI Render;
微任务:process.nextTick、promise、MutationObsever;
3. Nodejs的事件循环和浏览器事件循环区别?
Nodejs和浏览器端,宏任务和微任务交替执行,调用顺序基本相同。Nodejs执行会进行阶段区分,分为6个阶段:参考:Node.js 事件循环文档,每进入某个阶段,会从回调队列中取出函数执行。当队列为空或回调函数达到系统设定阈值,就进入下一个阶段。
异步方案
可以把ajax异步回调作为浏览器端的最初的异步解决方案,
异步回调 ———> Promise实例 ——> Generator ——> async/await
,大致是一个这样的线,我们需要关注的可能主要就是Promise 和 async/await的方案。1. Promise内部实现了解嘛?它的具体工作流程是怎么样的?
Promise是异步解决方案,包含异步操作结果的对象,特点:
内部存在三种状态,状态一旦变化不可更改状态;Promise是链式调用,每次调用then回调函数都会返回一个新的Promise,并且是一个全新的Promise;
Promise异步处理流:
执行Promise实例回调函数,由于异步请求或者操作,此时状态未变化。继续执行then回调,由于状态未变化回调会被放入回调数组中。直到Promise实例中异步请求或者操作完成,状态发生变化,调用resolve函数,回调数组遍历执行,then回调函数拿到相关数据
。2. 说一说async/await
参考:
Promise原理解析
图解Promise流程
浏览器渲染原理
浏览器是多进程应用,每打开一个Tab页,就相当于创建了一个独立的浏览器进程。浏览器进程有:Browser进程(主进程)、插件进程、GPU进程、渲染进程(浏览器内核)。主进程只有一个是负责协调应用,同时默认每个Tab页面一个渲染进程,互不影响。我们常说的Js线程、GUI渲染线程就包含在渲染进程之中,还包括异步http请求线程、事件触发线程等。
1. 地址栏输入域名地址之后发生了什么?
2. 浏览器渲染的流程?
存在阻塞的css资源时,浏览器会延迟JS的执行和DOM的构建;
3. 重绘和回流?
重绘
是当节点需要更改外观而不影响布局;回流
是布局或几何属性需要改变;参考:渲染性能
参考:
从浏览器多进程到JS单线程
你不知道的浏览器页面渲染机制
网络协议
关于TCP和UDP的介绍、TCP的三次握手和四次挥手就不细说,相关文章可以参考:传输层协议TCP和UDP
,TCP三次握手和四次挥手
;
http协议是常用的网络传输协议,全称是超文本传输协议,它规定了http请求和响应的具体结构,当然还包含其他东西,例如:缓存、文件类型、参数、请求类型、状态等。它是建立在传输层TCP协议之上的,TCP握手成功之后,才可以进行网络数据传输。
HTTP/HTTPS
1. 什么是http协议?它是怎么样的?
http是TCP/IP协议应用层协议,主要负责数据或文本图片等内容的传输,它是建立在传输层TCP协议之上的。http分为请求报文和响应报文,
从Web客户端发往Web服务器的HTTP报文称为请求报文(request message)。从服务器发往客户端的报文称为响应报文
,报文分为:起始行、 首部字段、主体等;2. http和https的区别?
http和https从字面的区别就是一个s,这个s就是SSL/TCL加密协议。说到加密协议就绕不开加密技术,在SSL/TCL加密协议中既有用到非对称加密,也有用到对称加密。SSL/TCL加密协议相当于是在应用层和传输层之间加了一层,可称为加密层。
大致流程:客户端向服务器端索要加密证书获取公钥等证书信息;双方协商生成"对话密钥";双方采用"对话密钥"进行加密通信。非对称加密保证"对话密钥"的安全传输,对称加密保证客户端和服务端对数据的加解密。
3. http网络缓存如何配置?
如果需要开启强缓存和协商缓存,可在服务端nginx web服务器进行对应的配置,开启对应的网络缓存。其他服务端web服务器也可配置。(配置细节网上一大堆)
4. 强缓存和协商缓存的区别?
强缓存:Cache-Control,常用属性有max-age、no-cache、no-store等。max-age表示相对时间内的缓存,在这个相对时间内不会再去请求对应资源;no-cache表示不意味着不缓存,它的意思是在使用缓存资源之前,它必须经过服务器的检查;
no-store表示不缓存。
协商缓存:Last-modified 和 ETag,这两个类似,可以理解为文件标识。也可以将ETag(你选择的版本ID)或者Last-modified日期添加到响应首部中。客户端下次获取资源时,他会分别通过If-None-Match(与ETage对应)和If-Modified-Since(与Last-Mofied对应)两个请求首部将值发送给服务器。如果服务器发现两次值都是对等的,就是返回一个HTTP 304。它们之间的区别:ETag 只要资源变化,它就会改变;Last-modified 不识别秒单位里的修改。
如何使用—————前端中保证HTML资源是最新的,设置如:max-age=300、ETag、Last-modified,当然也可考虑使用no-cache、ETag、Last-modified配合。而CSS和JS找资源已经被注入到HTML中,资源文件地址通常使用哈希值加入文件名中保证资源是最新,css和js文件可设置:max-age=31536000或last-modified 配合使用。
5. 了解http2.0嘛?为什么说http2.0更好?
http2.0基于二进制分帧层,http2.0可以在共享TCP连接的基础上同时发送请求和响应。在http1.x中,是通过文本的方式传输数据,基于文本的方式传输数据存在很多缺陷,文本的表现形式有多样性,因此要做到健壮性考虑的场景必然有很多,但是二进制则不同,只有0和1的组合,因此选择了二进制传输,实现方便且健壮。
为了保证http不受影响,那就需要在应用层(HTTP2.0)和传输层(TCP or UDP)之间增加一个二进制分帧层。在二进制分帧层上,http2.0会将所有传输的信息分为更小的消息和帧,并采用二进制格式编码,其中http1.x的首部信息会被封装到Headers帧,而Request Body则封装到Data帧。在传输中会共用一个TCP流(TCP连接中的一个虚拟通道,可以承载双向的消息),不至于重复连接。
参考:
书籍:HTTP权威指南
SSL/TLS协议运行机制的概述
前端框架
前端框架目前市面主流就是React和Vue,对于框架的使用和学习,前期建议多翻翻文档,中期根据自己在使用过程中遇到的问题学习,后期就可以考虑翻源码了。由于工作原因,我对react了解更多,所以分享主要就是React。
React和Vue作为前端框架在本质上做的是相同的事,在浏览器和开发操作之间加了一个中间层,来进项目的辅助管理和开发。
React框架
1. JSX本质是什么,它和JS的关系是什么?为什么使用JSX?
JSX
是类HTML的语法结构,实质是JS
的语法扩张。它语法结构简洁,通俗易懂,对于研发效率和体验有大的提升。2. JSX背后的功能模块是什么,这个功能模块做了哪些事情?
JSX
通过babel
语法转换之后,实际就是通过React.createElement
函数来创建React元素。createElement
接收三个参数type
类型,config
配置,children
子元素。通过createElement
就可创建出虚拟DOM
对象。3. react16.3新旧生命周期,消失的旧生命周期有哪些?
去掉
ComponentWillMount
和CompoentWillReceiveProps
升级为
getDeicvedStateFromProps
,保证生命周期更加单一,更可控;去掉ComponentWillUpdate新增getSnapshotDeforeUpdate;4. React团队为什么要去掉旧的生命周期函数?
React16+引入
Fiber
架构,Fiber
会将一个大的更新任务拆解为多个小任务,而且它是可中止,可恢复的。React16+生命周期被划分为render
和commit
两个阶段。render
阶段在执行过程中允许被打断,而commit阶段操作涉及真实DOM渲染,是不可打断的。ComponentWillMount
、ComponentWillUpdate
、ComponentWillReceiveProps
这些生命周期,它们都处于
render
阶段,而在Fiber
架构中,render
阶段会被打断,重复被执行。在这些生命周期可能习惯做的事情可能有:setState、异步请求、操作真实DOM等。而在Fiber异步渲染控制下,这些生命周期可能会导致非常严重的bug(例如在这些废弃的生命周期中调用支付接口)。5. React组件数据如何流动?实现数据通信的方案有哪些?
react是自上而下的单向组件数据流
6. 为什么是React Hooks?
相对于
Class
组件,函数组件更加轻量,更加符合UI=render(data)特点。同时在Fiber架构的加持下,Hooks的实现不是问题。配合函数组件的发展,Hooks应运而生,从而是函数组件真正把数据和渲染绑定到一起。当然Hooks也还是存在部分不足:部分周期不存在;不能很好的消化“复杂”,组件的拆分和组织是一个大的挑战,不易把握。7. 为什么Hooks执行顺序如此重要?
Hooks本质是链表。例如 使用useText、useState创建state时,hook创建的state会以单链表形式保存,更新时,函数组件重新调用,hooks会依次遍历单链表,读取数据并更新,这一过程完全按照创建时的顺序来的。因此当更新时,位置一旦改变,执行顺序被替换,运行就会出现bug。
8. 调和(协调)和diff的关系或区别?
调和指的是虚拟DOM映射到真实DOM的过程。调和过程并不能喝diff画等号。调和是“使一致”的过程,而diff是“找不同”的过程,它只是“使一致”过程中的一个环节。(当然常说的调和相关问题多半就是diff过程的)
9. react的diff逻辑和思路?
10. setState的工作流是怎么样的?
非并发(
concurrent
)模式:setState
会出现异步和同步的现象。在生命周期和合成事件中是同步,而在setTimeout、setInterval、DOM原生函数等函数中是同步的。那么这是为什么尼?在合成事件或生命周期执行时,批量更新的任务锁就被开启了,我们所做的setState操作会被放入到批量更新队列中,直到函数执行完,批量更新的任务锁才会被关闭。批量更新的任务锁是一个同步操作,而一旦你在setTimeout函数使用setState,此时setTimeout函数回调会被放入下一个宏任务执行,而当setState执行时,批量更新的任务锁时关闭的,它就不会放入到批量更新队列中,而是直接执行。并发(
concurrent
)模式:setState
不会出现异步和同步的现象。因为存在时间切片,只要当前时间片没有结束,依旧可以将多个 setState 合并成一个,即使是在setTimeout中被调用。而对于超过当前时间片的操作,会通过MessageChannel
放入到下一个宏任务中继续执行。(MessageChannel
接收消息的时机比 Promise 所在的 microTask 要晚,但是早于 setTimeout)11. Stack Reconciler栈调和 有怎么样的局限性?
浏览器中Js线程和渲染线程是互斥的。这两个线程不能穿插执行,必须串行。而当Js线程长时间占用主线程,那么渲染线程的更新就不得不长时间的等待,这时就会导致页面卡顿。
Stack Reconciler
栈调和是一个同步递归过程,虚拟DOM树diff算法遍历是深度优先遍历。由于它是同步的,不可在被打断。当处理结构复杂,体量庞大的虚拟DOM树时,Stack Reconciler
时间会很长,以为这Js主线程长时间占用主线程,进而导致上述中说道的渲染卡顿/页面卡死。12. 说一说Fiber架构?
特点:可中断、可恢复、存在优先级。
在
Fiber
架构模式下,每个更新任务会被赋予一个优先级。当然有任务A进入调度器,这个任务优先级更高,而Reconciler
中已有任务B在执行,那么,Reconciler
会将任务B终止,更高优先级的任务A被推入Reconciler
。当A任务完成之后,新一轮调度会将之前中断的任务B重新推入Reconciler
,继续它的渲染之旅。13. ReactDOM.render调用栈的初始化阶段、render阶段
初始化阶段:会创建root对象这个对象挂载
_internalRoot
属性,而_internalRoot
也就是FiberRoot
。FiberRoot
的本质是一个FiberRootNode
对象,其中包含current属性,current对象是一个FiberNode实例。current对象就是一个Fiber节点,并是Fiber树的头部节点;确定Fiber的优先级,结合优先级创建当前Fiber的update对象,并将其入队调度FiberRoot;接下来进入render阶段;(此时相当于只有一个Fiber头部节点)render阶段:通过createWorkInProgress函数,创建rootFiber节点的副本workInProgress节点树(即current节点的副本节点),他们通过alternate互相引用;接着会触发beginWork函数,进而实现对新的Fiber节点的创建。循环遍历,组件元素Fiber会不断被创建(每个元素节点对应一个Fiber节点),直到创建到最后一个为止,此时Fiber树(单链表)基本完成;重点,此时已经遍历到了单链表的最底部节点,然后会由下自上的依次生成真实DOM节点,同时被它的父组件副作用链,这个副作用链也是一个单链表,直遍历到根节点,此时的根节点上的副作用链就包含的全部的DOM更新。那么剩下的只需要拿到root下的副作用链更新即可了。
参考:
修言 深入浅出搞定 React
React 架构的演变 - 从同步到异步
React 架构的演变 - 从递归到循环
React 架构的演变 - 更新机制
React 架构的演变 - Hooks 的实现
性能优化
可使用Chrome Lighthouse进行性能测评,根据测评结果也可以得出一些改进的点:
react框架层面可以做的优化方向核心点:减少重新 render 的次数;减少计算的量,主要是减少重复计算。有下列具体方案:
一个前端项目下通用的优化技巧:使用缓存、节流、压缩、按需加载、全局管理等方法或技巧。如下:
以上更多的是各种技巧和原则,如果要知道具体的标准,可以参考google为Web性能表现提供的文档developers.google.cn/Web Performance
设计模式
参考文章:https://www.yuque.com/yopai/pp6bv5/mtu8xy
结尾
以上内容是以前端面试之道目录结构作为大纲进行的系统的整理,有修改也有添加,其中的内容大部分都是查看博客和相关资料获取的,因为自己也有薄弱的地方,所以有些目录下的内容偏少。如果有有更多补偿可以评论或者单独发我,谢谢✍✍。
The text was updated successfully, but these errors were encountered: