文章目录

  • 1.前端架构职责
  • 2.架构角度对三剑客的理解
    • html:
    • CSS:
    • JS:
  • 3.技术规范的意义
    • 技术选型
    • 资源管理
  • 4.前端安全
    • 跨站脚本攻击
  • 5.性能优化
    • 性能瓶颈
    • 浏览器请求并发数限制
    • 代码层及优化
        • 【DOM层级优化】
        • 【Link标签】
        • 【少用iframe】
        • 【CSS】
        • 【JS】
    • 资源加载优化
    • 浏览器架构与渲染原理
      • 进程和线程
      • 浏览器的多进程架构
  • iframe|qiankun|emp
    • iframe
    • qiankun(基座)
    • emp
    • 总结

1.前端架构职责

  • 设计合理的前端技术机构
  • 搭建高效的前端工程

必要性

  • 现在的前端框架难以满足日益增长的功能需求,会导致碎片化越来越严重,越来越无序

    最后的结果就是达到难以继续维护和扩展的阈值,便会得到一种极端的结果,那就是彻底重构

解决:

​ 通过前端架构师,有效的干预利用软件架构,保持系统的有序

​ 通过合理的解耦各个组件和层级的功能来提高系统的高效性和灵活性,使得所有组件层级在完成各自功能的同时组合为完整的软件系统。

前端架构师(前端技术专家)的工作:

  • 选择可提高开发和维护效率的工具和框架
  • 制定相应的开发规范
  • 组件化,规划基础组件和业务组件
  • 前后端分离,将前端开发实现开发、维护、部署、发布的相对独立性提高开发效率和快速响应问题
  • 性能优化,加载性能和执行性能

2.架构角度对三剑客的理解

html:

客户端渲染

一般的流程是浏览器向网站发起请求,服务器接收到请求后立即返回静态的html部分,这部分的内容通常是与用户无关的静态数据内容,浏览器去解析静态的html文档,等待js脚本加载完成后,发起异步请求来获取动态数据,服务器接收到异步请求之后,查询数据库,并将动态的数据返回给浏览器,浏览器接收到动态数据以后,js通过编译,将数据变成html字符串,并渲染为可视化的UI。

劣势:首屏渲染速度慢,对seo不太友好。

优势:更好的支持离线场景和前后端分离方案的实施。并且随着vue,react,angular框架的普及,对于存在大量动态数据渲染的情况来说,客户端渲染优势明显。

抛开seo问题来说,客户端渲染在大多数场景下都是优于服务端渲染的场景的。尤其是在移动端的场景下。虚拟DOM可以保证动态渲染的良好性能。因为vue,react都是基于虚拟DOM的,而基于组件的前端路由管理,无论是从速度还是灵活性都优先于依赖于服务端路由驱动的MVC的模式。

服务端渲染

一般的流程是浏览器向网站发起请求,服务器接收到请求后,先查询数据库中的动态数据,然后将数据通过模板引擎编译为html字符串返回给浏览器,浏览器接收到html文件后,渲染为可视化的UI。

服务端渲染相对于客户端渲染的优势在于:

其支持seo并且首屏时间较短。

CSS:

样式预处理

less,流行的预处理方式之一

具备特殊语法规范,可编译为css的开发框架更为合适,弥补了css的逻辑处理和复用性方面的不足,引入了变量和混合模块集成等特性,同时支持编程和维护的嵌套语法,从细节上提升了css的开发和维护效率。

缺陷:

大而全——一旦选择预处理语言,就必须接受它的全部规范和功能;

难扩展——缺少插件生态;

样式后处理

postcss

postcss 一种对css编译的工具,类似babel对js的处理;

postcss 只是一个工具,本身不会对css一顿操作,它通过插件实现功能,autoprefixer 就是其一。

与 less sass 的区别

less sass 是预处理器,用来支持扩充css语法。

postcss 既不是 预处理器也不是 后处理器,其功能比较广泛,而且重要的一点是,postcss可以和less/sass结合使用

JS:

技术选型

底层技术栈——解决什么问题

实现层技术栈——出于学习曲线和生态等综合考量

复杂的cms系统,使用TS或者flow为js加入静态类型属于底层技术栈,解决底层问题,vue、angular属于实现层技术栈。

代码规范

eslint校正

一种逻辑可以多种方案实现,如何选择最优方案

比如js异步编程:是选择常规的回调函数还是promise,在promise基础上使用Generate 还是aysnc、await。

通过合理的封装实现,实现方案代码的正确和合理性是无法通过工具监测的,所以需要认为评审。

3.技术规范的意义

  • 大型项目最复杂的模块往往仅占整体的一小部分,更多的是相对简单的日常开发和维护,遵循统一的技术规范,能够有效的降低多人协作项目交接过程中的沟通成本。
  • 如果在项目中缺少文档,代码不规范,资源管理混乱。将会导致项目开发的效率非常低下。

技术选型

  • 功能
  • 性能
  • 稳定性
  • 生态
  • 学习曲线
  • 作者
  • 社区
  • 开源协议

资源管理

目录结构

命名规范

4.前端安全

跨站脚本攻击

  • Cross Site Script(CSS或)

    指黑客通过“HTML注入”篡改了网页,插入了恶意的脚本(主要是JS脚本),从而在用户浏览网页时,控制用户浏览器的一种攻击

    常见的跨站脚本攻击:

    1. 挂马
    2. 盗取用户Cookie
    3. 钓鱼攻击,高级的钓鱼技巧
    4. 删除目标文章、恶意篡改数据、嫁祸
    5. 劫持用户web行为,甚至进一步渗透内网
    6. 爆发Web2.0蠕虫
    7. 蠕虫式挂马攻击、刷广告、刷流量、破坏网上数据
    8. 其它安全问题
  • 常见跨站脚本攻击分类

    1. 反射型XSS

      非持久性XSS,简单的把用户输入的数据“反射”给浏览器,即黑客往往需要诱使用户点击一个恶意链接,攻击才能成功。用户通过点击这个恶意链接,可以成功获取用户隐私数据的一种方式。如:盗取用户Cookie信息、破坏页面结构、重定向到其他网站、盗取内网IP等。

    2. 存储型XSS

      持久性XSS,它会将用户输入的数据存储在攻击方的服务器上,具有很强的稳定性。

      例如:访问某黑客写下的一篇含有恶意js代码的博客文章,黑客把恶意脚本保存到服务端。

    3. DOM Based XSS

      从效果上来说,也是反射型XSS。其形成是通过修改页面的“DOM”节点形成的XSS。

5.性能优化

资源加载阶段

  • 白屏时间

    页面开始展示的时间点-开始请求时间点

  • 首屏时间

    首屏内容渲染结束时间点(视业务具体情况而定)-开始请求时间点

  • 可交互节点

    可交互时间=用户可以正常进行事件输入时间点-开始请求时间点

  • 首次有效绘制

    优先级最高的内容被渲染的时间点

可交互阶段

  • 反馈速度

    鼠标点击、滚动操作时,页面的响应速度

  • 动画帧率

    最佳为每秒60帧

(增加用户的耐心度,给予用户反馈,转移用户注意力)

性能瓶颈

  • 频繁操作dom元素导致页面过多的重排和重绘,浏览器不得不频繁地计算布局,重新排列与绘制页面元素,导致浏览器产生巨大的性能开销
  • 重排:浏览器第一次渲染页面布局之后,后续引起页面各个元素点在页面所处位置的重新计算与重新布局的行为称之为重排
  • 重绘:布局计算完成之后,页面重新绘制,这时浏览器会遍历渲染树,绘制每个节点这种行为叫作重绘

浏览器请求并发数限制

目前主流的浏览器并发请求数都是6

  • 当页面加载时需要的资源都是从服务端过来的一个个请求。

    比如有30个请求,实际上浏览器处理这些请求时并不是一次性将20个请求一起发过去,而是有请求并发限制,减少处理时浏览器本身的线程切换开销。谷歌 他实际上也是6条并发进行,某一条请求完成后补充另外的请求进来,直到30条请求处理完毕

  • 多域名访问。

    由于浏览器的请求并发限制针对的是同一个域名下的资源,将静态资源与服务分离,分多域名储存,就可以以最简单的方式解决浏览器的并发瓶颈

代码层及优化

【DOM层级优化】

浏览器在解析HTML文件并构建DOM数的过程中,会将我们写的标签向DOM树中挂载,层级越深,DOM树就越深。DOM树在实际的访问中是需要遍历的,每增加一层遍历时间和复杂度都是指数增长,在构建DOM树的过程中层级越深所需要的时间会越长,计算时所需要消耗的内存就越大。

【Link标签】

<link rel="prefetch" href="common.css“ as="style">

网站的性能提升决定于缓存,能从缓存中加载资源就不去服务器加载。prefetch的原理实际上是利用浏览器空闲时间先下载用户指定需要的内容,然后缓存起来,用户下次加载时,实际上是从缓存加载,此时会发现请求的状态码是304;

prefetch最大的作用不在于当前页面,而在于后续可能会访问的页面上。

<link rel="preload" href="common.css“ as="style">

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SPgwvnhg-1648432797502)(C:\Users\czzhao3\AppData\Roaming\Typora\typora-user-images\1648087869591.png)]

【少用iframe】

由于iframe的隔离性,嵌套的页面本身引用的css和js可能已经存在,但还是会重复加载,iframe相当于一个大的DOM节点,里面的样式和事件都在,影响页面的效率。

【CSS】

  • 雪碧图

  • 减少昂贵的样式成本(过度、渐变、阴影、圆角、透明度)

  • 避免float

  • 相比普通的文档流排列布局,float的排列方式在浏览器端的实现需要更多的计算量

    会造成父元素塌陷,margin失效、需要清除浮动

【JS】

  • 及时清除定时器(定时器中有dom操作)
  • 多利用事件委托
  • 避免重复的事件监听
  • 慎用闭包
  • 函数节流和防抖(减少浏览器重绘重排)

资源加载优化

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ajJkqvDc-1648432797504)(C:\Users\czzhao3\AppData\Roaming\Typora\typora-user-images\1648088187670.png)]

浏览器架构与渲染原理

进程和线程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kz0lZ684-1648432797505)(C:\Users\czzhao3\AppData\Roaming\Typora\typora-user-images\1648088364328.png)]

浏览器的多进程架构

Chrome:

浏览器进程把数据交给了渲染进程。

  • DOM加载

    当渲染进程接收到导航的确认信息后,开始接受来自浏览器进程的数据,这时,主线程会解析数据转化为DOM对象,DOM为web开发人员通过js与网页进行交互的数据结构与API。

  • 子资源加载

    在构建DOM的过程中,会解析到图片、CSS、JS脚本等资源,这些资源都是需要从网络或者缓存中获取的,主线程在构建DOM过程中如果遇到了这些资源,逐一发起请求去获取。

  • JS的下载与执行

  • 样式计算

  • 布局

  • 绘制

  • 合成

iframe|qiankun|emp

微前端:

  1. js沙箱:子应用之间互不影响,包括全局变量,事件等处理
  2. css隔离:子应用之间样式互不影响,切换时装载和卸载
  3. HTML Entry:ConfigEntry的进阶版,把入口简化掉,把解析消耗留给用户
  4. Config Entry:配置每个子应用的JS和CSS,包括内联的那些
  5. 按需加载:切换到页面时才加载相应的HTML、CSS和JS
  6. 公共依赖加载:大部分子应用都用到的资源怎么处理
  7. 预加载:空闲时加载子应用资源,用户行为数据支持
  8. 父子应用通讯:子应用如何调父应用方法,父应用如何下发状态
  9. 子应用嵌套:微前端如何嵌套微前端——进阶用法
  10. 子应用并行:多个微前端如何同时存在进阶用法

iframe

提供了浏览器原生的硬隔离方案,隔离了样式和js;并且完美模拟了多标签页,

优异的隔离性,彻底隔绝了应用间上下文,导致内存变量无法被共享。

问题:

  1. 父子之间的网页链接是不同步的,浏览器一刷新,iframe中的状态就没了,后退、前进按钮无法使用——可以解决
  2. 父子之间的UI难以同步,内嵌的iframe并不会自动调节宽高,一旦需要通信交互就很难受——难解决
  3. 全局上下文完全隔离,内存变量不共享,则需要完成iframe之间的通信及变量同步设计——难解决
  4. 慢,每次进子应用,浏览器都需要重新完整加载资源——可以忍受

qiankun(基座)

所有应用都注册在基座上,通过基座应用来监听路由,并按路由规则来加载不同的应用,来实现应用间解耦。

qiankun通过html文件作为应用入口,然后通过一个html解析器,从文件中提取js和css依赖,然后再通过fetch下载依赖,于是在qiankun中可以这样配置入口,qiankun会通过import-html-entry请求http://example.com得到对应的html文件,解析内部所有的script和style标签,依次下载和执行他们,这使得应用加载变得更为好用了。同时,能够确保在隔离的沙箱环境中执行。

const APPS=[{entry:"",container:"root",activeRule:"/app_1"}]

要保证js和css隔离

针对js,qiankun使用了proxy和快照两个模式来处理隔离

1.proxy

把解析所得的script标签用with(window){} 的函数包裹起来,然后把window.proxy作为函数的第一个参数传进去,所以with语法里面的window实际上是window.proxy.

这样在执行这段代码时,所有

var name='张三'

这样的语句所添加的全局变量name,实际上是被挂载到window.proxy上,而不是真正的全局window上,当应用被卸载时,对应的proxy会被清除,所以不会导致js被污染。而在IE11等不支持proxy特性的浏览器上,就会使用快照模式来保证兼容性。

2.快照模式

在加载应用前,将window上的所有属性保存起来(拍摄快照),应用被卸载时,再恢复window上的所有属性,所以也可以防止页面污染。但是当页面同时存在多个应用实例的时候,qiankun就无法把它们隔离开了。所以IE下的快照策略并不支持多实例模式。

针对css,qiankun同样有两套方案来处理隔离

1.基于Shadow Dom来完成

Shadow Dom——https://www.cnblogs.com/yf2196717/p/14732459.html

使用strictStylesolution的时候,qiankun将采用Shadow Dom的方式来采取样式隔离,也就是为子应用的根节点创建一个Shadow root,最终,整个应用的所有DOM都会绘制成一颗Shadow Tree,而我们知道Shadow DOM的特点是:它内部所有节点的样式对树外面的节点是无效的,因此自然的实现了样式隔离。但是,某些UI框架可能需要一些弹窗,它是直接挂载到document.body上面的,这个时候就脱离shadow tree,所以他的样式仍然会对全局造成污染。

2.类似Vue的Scope属性

为子应用的根节点添加一个特定的随机属性,开启后如下所示:

.main{}===>div[data-qiankun-a2db3cf12] .amain{​font-size?10px;}

虽然有用,但是对于@keyframes、@font-face、@import、@page的支持还存在适配问题。

qiankun提供了一个简要的适配方案,思路是基于一个全局的GlobalState对象,这个对象由基座应用来负责创建,内部包含了一组用于通信的变量,以及两个分别用于修改变量值和监听变量变化的方法,setGlobalState和ontGlobalStateChange。即通过订阅全局变量的修改状态来实现通信,是标准的订阅-发布模式。

qinkun2.0中提供了更为简单的一种模式:

基于props通信的API,主要解决父子应用强耦合时的通信,所以qiankun总体上属于轻量级的微前端框架。接口简单,功能丰富。

emp

基于webpack5的Module Federation来实现,即去中心化。

在qianlun的模式下,通过中心基座集成各微应用,而在emp中不需要这样一个中心化的基座。

emp中每一个微应用都可以通过远程调用的方式,引入共享模块。

webpack5的重要特性:Module Federation

目的在于将多个独立的构建应用组成一个应用程序,通俗的来讲,Module Federation提供了能在当前应用中远程加载其他服务器上应用的能力,比较接近后端微服务的概念。

由此可以提出两个概念:

  1. host——引用其他应用的应用
  2. remote——被其他应用所使用的应用
//Shell(Host)import('mfe1/Cmp')remotes:{mfe1:"mfe1"}//Microfrontend(Remote)exposes:{Cmp:'./my.cmp.ts'}

新开发的项目,可以直接使用emp-cli,

老项目需要迁移升级开发工具链,例如webpack至少要升级到webpack5.然后再和emp-cli相适应调整。

总结

iframe:

特点:天生隔离样式与脚本、多页

缺点:

  • 不是单页应用,会导致浏览器刷新iframe Url状态丢失、后退前进按钮无法使用;
  • 弹框类的功能无法应用到整个大应用中,只能在对应的窗口内展示;
  • 由于可能应用间不是在相同的域内,主应用的cookie要透传到根域名都不同的子应用中才能实现免登录效果;
  • 每次子应用进入都是一次浏览器上下文重建、资源重新加载的过程,占用大量资源的同时,也在极大地消耗资源;
  • iframe的特性导致搜索引擎无法获取到其中的内容,进而无法实现应用的seo;

qiankun:

特点:中心化

缺点:

  • css隔离方案并不完美(沙箱隔离、HTML Entry接入方式、资源预加载)

emp:

特点:每个微应用独立部署运行

缺点:

  • 目前无法涵盖所有框架(动态更新微应用、去中心化、跨技术栈组件式调用、按需加载、应用间通信、生成对应技术栈模板、远程拉取ts声明文件)