前端总结

1. 微前端

描述:将前端应用分解成一些更小、更简单的能够独立开发、测试、部署的小块,而在用户看来仍然是内聚的单个产品。

特点:

  • 代码库更小,更内聚、可维护性更高
  • 松耦合、自治的团队可扩展性更好
  • 渐进地升级、更新甚至重写部分前端功能成为了可能

团队自治:应该围绕业务功能纵向组建团队,而不是基于技术职能划分。最简单的,可以根据最终用户所能看到的内容来划分,比如将应用中的每个页面作为一个微前端,并交给一个团队全权负责。与基于技术职能或横向关注点(如样式、表单、校验等)组织的团队相比,这种方式能够提升团队工作的凝聚力

多 Bundle 集成

微前端架构中一般会有个容器应用(container application)将各子应用集成起来,职责如下:

  • 渲染公共的页面元素,比如 header、footer
  • 解决横切关注点(cross-cutting concerns),如身份验证和导航
  • 将各个微前端整合到一个页面上,并控制微前端的渲染区域和时机

集成方式:每个子应用暴露出渲染函数,主应用在启动时加载各个子应用的独立 Bundle,之后根据路由规则渲染相应的子应用。目前看来,是最灵活的方式

应用间通信通过自定义事件间接通信是一种避免直接耦合的常用方式、路由参数也可以作为一种通信手段

(原则上,无论采用哪种方式,都应该尽可能减少子应用间的通信,以避免大量弱依赖造成的强耦合)

缺点:

  • 导致依赖项冗余,增加用户的流量负担
  • 团队自治程度的增加,可能会破坏协作

总结:

  • 技术架构上进一步的扩展性(模块边界清晰、依赖明确)
  • 团队组织上的自治权
  • 开发流程上能独立开发、独立交付

最大的意义在于解锁了多技术栈并存的能力,尤其适用于渐进式重构中架构升级过渡期。允许低成本尝试新技术栈,甚至允许选用最合适的技术栈做不同的事情。

 

参考:https://zhuanlan.zhihu.com/p/96464401

 

2.React生命周期

React的生命周期从广义上分为三个阶段:挂载、渲染、卸载

1. 挂载卸载过程

(1)constructor()

         constructor()中完成了React数据的初始化,它接受两个参数:props和context。只要使用了constructor()就必须写super(),否则会导致this指向错误。

(2)componentWillMount()

         一般用的比较少,它更多的是在服务端渲染时使用。它代表的过程是组件已经经历了constructor()初始化数据后,但是还未渲染DOM时。

(3)componentDidMount()

          组件第一次渲染完成,此时dom节点已经生成,可以在这里调用ajax请求,返回数据setState后组件会重新渲染

(4)componentWillUnmount ()

         在此处完成组件的卸载和数据的销毁。

         ①.clear你在组建中所有的setTimeout,setInterval

         ②.移除所有组建中的监听 removeEventListener

2.更新过程

(1)componentWillReceiveProps(nextProps)

         ①.在接受父组件改变后的props需要重新渲染组件时用到的比较多

         ②.接受一个参数nextProps

         ③.通过对比nextProps和this.props,将nextProps的state为当前组件的state,从而重新渲染组件

(2)shouldComponentUpdate(nextProps,nextState)

         ①.此方法仅作为性能优化的方式而存在。不要企图依靠此方法来“阻止”渲染,因为这可能会产生意外的问题

         ②.唯一用于控制组件重新渲染的生命周期,由于在react中,setState以后,state发生变化,组件会进入重新渲染的流程,在这里return false可以阻止组件的更新

(3)componentWillUpdate(nextProps,nextState)

         shouldComponentUpdate返回true以后,组件进入重新渲染的流程,进入componentWillUpdate,这里同样可以拿到nextProps和nextState。

(4)componentDidUpdate(prevProps,prevState)

         组件更新完毕后,react只会在第一次初始化成功会进入componentDidmount,之后每次重新渲染后都会进入这个生命周期,这里可以拿到prevProps和prevState,即更新前的props和state。

(5)render()  

         render函数会插入jsx生成的dom结构,react会生成一份虚拟dom树,在每一次组件更新时,在此react会通过其diff算法比较更新前后的新旧DOM树,比较以后,找到最小的有差异的DOM节点,并重新渲染。

参考:https://www.jianshu.com/p/b331d0e4b398

 

3.React组件通信

1.父组件向子组件通信

   父组件通过向子组件传递 props,子组件得到 props 后进行相应的处理。

2.子组件向父组件通信

   利用回调函数,可以实现子组件向父组件通信:父组件将一个函数作为 props 传递给子组件,子组件调用该回调函数,便可以向父组件通信。

3.跨级组件通信

   (1)层层组件传递props:通过中间组件进行通信。

   (2)使用 context 对象:context是一个全局变量,像是一个大容器,在任何地方都可以访问到,我们可以把要通信的信息放在context上,然后在其他组件中可以随意取到。(但是React官方不建议使用大量context)

4.非嵌套组件间通信

    (1)共同的父组件:通过共同的父组件进行通信。

    (2)通过自定义事件:引入events包,通过自定义事件的发布/订阅模式进行通信。

参考:https://www.jianshu.com/p/fb915d9c99c4

 

4.跨域的通信方式

1、JSONP

     在CORS和postMessage以前,我们一直都是通过JSONP来做跨域通信的。

     JSONP的原理:通过<script>标签的异步加载来实现的。比如说,实际开发中,我们发现,head标签里,可以通过<script>标签的src,里面放url,加载很多在线的插件。这就是用到了JSONP。

2、WebSocket

     主要用于服务端向前端发送消息。

3、CORS

     CORS 可以理解成是既可以同步、也可以异步*的Ajax。

     如果面试官问:“CORS为什么支持跨域的通信?”

     答案:跨域时,浏览器会拦截Ajax请求,并在http头中加Origin。

4、Hash

     Hash的改变,页面不会刷新

5、postMessage

     H5中新增的postMessage()方法,可以用来做跨域通信。

参考:https://blog.csdn.net/liwb94/article/details/85066065

 

5.http缓存

http缓存都是从第二次请求开始的。第一次请求资源时,服务器返回资源,并在respone header头中回传资源的缓存参数;第二次请求时,浏览器判断这些请求参数,命中强缓存就直接200,否则就把请求参数加到request header头中传给服务器,看是否命中协商缓存,命中则返回304,否则服务器会返回新的资源。

1.强缓存

   强制缓存在缓存数据未失效的情况下(即Cache-Control的max-age没有过期或者Expires的缓存时间没有过期),那么就会直接使用浏览器的缓存数据,不会再向服务器发送任何请求。强制缓存生效时,http状态码为200。

   优先级:Pragma > Cache-control > Expires

2.协商缓存

   浏览器第二次请求时就会与服务器进行协商,与服务器端对比判断资源是否进行了修改更新。如果服务器端的资源没有修改,那么就会返回304状态码,告诉浏览器可以使用缓存中的数据,这样就减少了服务器的数据传输压力。如果数据有更新就会返回200状态     码,服务器就会返回更新后的资源并且将缓存信息一起返回。

   Last-Modified与ETag是可以一起使用的,服务器会优先验证ETag,一致的情况下,才会继续比对Last-Modified,最后才决定是否返回304。

3.为什么要使用缓存

  • 减少了冗余的数据传输,节省了网费。
  • 缓解了服务器的压力, 大大提高了网站的性能
  • 加快了客户端加载网页的速度

6.Vue3和Vue2响应式原理的区别

     Object.defineProperty 不能监听对象属性新增和删除,在初始化阶段递归执行劫持对象属性,性能损耗较大;而 Proxy 可以监听到对象属性的增删改,在访问对象属性时才递归执行劫持对象属性,在性能上有所提升。不过 Proxy API 属于 ES6 规范,目前 IE 尚不支持。

 

7.https

Q: HTTPS 为什么安全?
A: 因为 HTTPS 保证了传输安全,防止传输过程被监听、防止数据被窃取,可以确认网站的真实性。

Q: HTTPS 的传输过程是怎样的?
A: 客户端发起 HTTPS 请求,服务端返回证书,客户端对证书进行验证,验证通过后本地生成用于改造对称加密算法的随机数,通过证书中的公钥对随机数进行加密传输到服务端,服务端接收后通过私钥解密得到随机数,之后的数据交互通过对称加密算法进行加解密。

Q: 为什么需要证书?
A: 防止”中间人“攻击,同时可以为网站提供身份证明。

Q: 使用 HTTPS 会被抓包吗?
A: 会被抓包,HTTPS 只防止用户在不知情的情况下通信被监听,如果用户主动授信,是可以构建“中间人”网络,代理软件可以对传输内容进行解密。

 

8.手写call、apply和bind

1、call

 

Function.prototype.callxyz = function (context, ...args) {
    context = context || window;

    const fnSymbol = Symbol("fn");
    context[fnSymbol] = this;

    context[fnSymbol](...args);
    delete context[fnSymbol];
};

2、apply

Function.prototype.applyxyz = function (context, argsarr) {
    context = context || window;

    const fnSymbol = Symbol("fn");
    context[fnSymbol] = this;

    context[fnSymbol](...argsarr);

    delete context[fnSymbol];
};

3、bind

  Function.prototype.bindxyz = function (context, ...args) {
    context = context || window;

    const fnSymbol = Symbol("fn");
    context[fnSymbol] = this;

    return function (..._args) {
      args = args.concat(_args);
      context[fnSymbol](...args);
      delete context[fnSymbol];
    };
  };

 

总结:核心思想都是将该函数转化为指定对象的一个属性,然后在指定对象的作用域下去执行函数。

 

9.手写Promise

class MyPromise {
  constructor(fn) {
    this.resolvedCallbacks = [];
    this.rejectedCallbacks = [];
    
    this.state = 'PENDING';
    this.value = '';
    
    fn(this.resolve.bind(this), this.reject.bind(this));
    
  }
  
  resolve(value) {
    if (this.state === 'PENDING') {
      this.state = 'RESOLVED';
      this.value = value;
      
      this.resolvedCallbacks.map(cb => cb(value));   
    }
  }
  
  reject(value) {
    if (this.state === 'PENDING') {
      this.state = 'REJECTED';
      this.value = value;
      
      this.rejectedCallbacks.map(cb => cb(value));
    }
  }
  
  then(onFulfilled, onRejected) {
    if (this.state === 'PENDING') {
      this.resolvedCallbacks.push(onFulfilled);
      this.rejectedCallbacks.push(onRejected);
      
    }
    
    if (this.state === 'RESOLVED') {
      onFulfilled(this.value);
    }
    
    if (this.state === 'REJECTED') {
      onRejected(this.value);
    }
  }
}
      

 

10.性能优化

性能问题无外乎两方面原因:渲染速度慢、请求时间长。

1.script 标签:调整加载顺序提升渲染速度

  • async 属性。立即请求文件,但不阻塞渲染引擎,而是文件加载完毕后阻塞渲染引擎并立即执行文件内容。如果与 DOM 和其他脚本依赖不强时,使用 async。
  • defer 属性。立即请求文件,但不阻塞渲染引擎,等到解析完 HTML 之后再执行文件内容。如果依赖其他脚本和 DOM 结果,使用 defer。
  • HTML5 标准 type 属性,对应值为“module”。让浏览器按照 ECMA Script 6 标准将文件当作模块进行解析,默认阻塞效果同 defer,也可以配合 async 在请求完成后立即执行。

                                                                                                                                                     注:绿色的线表示执行解析 HTML ,蓝色的线表示请求文件,红色的线表示执行文件。

2.link 标签:通过预处理提升渲染速度

  • dns-prefetch。当 link 标签的 rel 属性值为“dns-prefetch”时,浏览器会对某个域名预先进行 DNS 解析并缓存。这样,当浏览器在请求同域名资源的时候,能省去从域名查询 IP 的过程,从而减少时间损耗。下图是淘宝网设置的 DNS 预解析。
  • preconnect。让浏览器在一个 HTTP 请求正式发给服务器前预先执行一些操作,这包括 DNS 解析、TLS 协商、TCP 握手,通过消除往返延迟来为用户节省时间。
  • prefetch/preload。两个值都是让浏览器预先下载并缓存某个资源,但不同的是,prefetch 可能会在浏览器忙时被忽略,而 preload 则是一定会被预先下载。
  • prerender。浏览器不仅会加载资源,还会解析执行页面,进行预渲染。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值