专业技能
一般来说,面试官会根据你的简历内容去提问,但是技术基础还有需要自己去准备分类,形成自己的知识体系的。简单列一下我自己遇到的一些题
- HTML+CSS
- JavaScript
- 前端框架
- 前端性能优化
- 前端监控
- 模块化+项目构建
- 代码管理
- 信息安全
- 网络协议
- 浏览器
- 算法与数据结构
- 团队管理
- 开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
最近得空把之前遇到的面试题做了一个整理,包括我本人自己去面试遇到的,还有其他人员去面试遇到的,还有网上刷到的,我都统一的整理了一下,希望对大家有用。
其中包含HTML、CSS、JavaScript、服务端与网络、Vue、浏览器等等
由于文章篇幅有限,仅展示部分内容
-
微前端是什么
-
背景
-
目标
-
达成价值
-
缺点
-
Part 02 架构与工程
-
微前端方案有哪些
-
架构设计选型注意点
-
需求分析
-
设计原则
-
应用架构图
-
系统拆分
-
时序图
-
前端流程图
-
Part 03 关键技术
-
关键技术一览
-
架构核心
-
注册中心
-
代码复用
-
子应用
-
Part 04 项目实施
-
立项前的心路
-
参考微前端资料
-
进行PC架构优化计划
-
风险
-
迭代立项
-
进展
-
后续计划
Part 01 “大话”微前端
把这个事情的前因后果讲清楚
微前端是什么
想要回答这个问题直接给一个定义其实没那么难,但是没接触过的同学未必理解。所以需要先介绍一下背景,再解释会更容易明白。
web发展1
这张图,展示了软件开发前端后分工的三个时期:
-
单体应用:在软件开发初期和一些小型的Web网站架构中,前端后端数据库人员存在同一个团队,大家的代码资产也在同一个物理空间,随着项目的发展,我们的代码资产发展到一定程度就被变成了巨石。
-
前后端分离:前端和后端团队拆分,在软件架构上也有了分离,彼此依靠约定去协作,大家的生产资料开始有了物理上的隔离。
-
微服务化:后端团队按照实际业务进行了垂直领域的拆分单一后端系统的复杂度被得到分治,后端服务之间依靠远程调用去交互。这个时候前端需要去调用后端服务时候,就需要加入一层API网关或者BFF来进行接入。
web发展2
现在很多互联网公司的研发团队的工作模式更靠近这种,把整个产品拆分成多个阿米巴模式的业务小组。
在这种研发流程和组织模式下,后端的架构已经通过微服务化形成了拆分可调整的形态,前端如果还处于单体应用模式,不谈其它,前端的架构已经给协作带来瓶颈。
另外 Web 3.0 时代来临,前端应用越来越重,随着业务的发展迭代和项目代码的堆积,前端应用在勤劳的生产下演变成了一个庞然大物。人关注复杂度的能力有限,维度大概维持在5~8左右。单体应用聚合的生产资料太多,带来复杂性的维度太多,也容易引发更多的问题。简而言之,传统的SPA已经没办法很好的应对快速业务发展给技术底层的考验。
我们的产品和前端项目也同样遇到了这个问题。如何解决这个问题呢?
其实后端的发展已经给出了可借鉴的方案,在理念上参照微服务/微内核的微前端架构应时而生。
想要解决这个问题,在吸引力法则的指引下我们遇到了微前端架构,也验证了它的确帮助我们解决了这个难题。
现在给出我们的微前端这样一种定义:
微前端是一种类似于微内核的架构,它将微服务的理念应用于浏览器端,即将 Web 应用由单体应用转变为多个小型前端应用聚合为一的应用。多个前端应用还可以独立运行、独立开发、独立部署。
背景
背景
-
美业PC作为一个单体应用经历4年迭代开发,代码量和依赖庞大,纯业务代码经统计有60多万行
-
工程方面,构建部署的速度极慢,开发人员本地调试体验差效率低,一次简单的构建+发布需要7+8=15分钟以上
-
代码方面,业务代码耦合严重,影响范围难以收敛,多次带来了“蝴蝶效应”式的的线上Bug和故障
-
技术方面,通用依赖升级带来的改动和回归成本巨大,涉及例如Zent组件、中台组件等依赖包相关的日常需求和技术升级几乎不可推动
-
测试方面,单应用应对多人和多项目发布,单应用发布总和高且非常频繁,每次的集成测试都有冲突处理和新问题暴露的风险
-
组织方面,单应用也无法很好应对业务小组的开发组织形式,边界职责不清晰且模块开发易干扰
-
架构方面,前端无法和后端形成对应的领域应用开发模式,不利于业务的下沉,也无法支持前端能力的服务化和对技术栈的演进依赖
总体来说,臃肿的单体应用模式,给开发人员带来了无法忍受的难处,给快速支撑业务带来了很大的瓶颈,也没有信心应对接下来的业务的继续拓展。对美业PC进行架构调整就是非常迫切和有价值的事情了
目标
-
业务架构层面,围绕美业PC的业务形态、项目架构以及发展趋势,将大型多团队协同开发的前端应用视为多个独立团队所产出功能的组合。
-
技术架构层面,解耦大型前端应用,拆分成基座应用、微前端内核、注册中心、若干独立开发部署的子系统,形成分布式体系的中心化治理系统。
-
软件工程方面,保证渐进式迁移和改造,保证新老应用的正常运行。
达成价值
业务价值
-
实现了前端为维度的产品的原子化,如果整合新业务,子应用可以快速被其他业务集成
-
以业务领域划分,让组织架构调整下的项目多人协作更职责清晰和成本低,且适应组织架构调整
-
减慢系统的熵增,铺平业务发展道路。
工程价值
-
实现了业务子应用独立开发和部署,构建部署的等待耗时从15分钟降到了1分半
-
支持渐进式架构,系统子应用之间依赖无关,可以单个升级依赖,技术栈允许不一致,技术迭代的空间更大
-
前端能力能够服务化输出
-
架构灵活,新的业务可以在不增加现存业务开发人员认知负担的前提下,自由生长无限拓展
缺点
一个架构的设计其实对整体的一个权衡和取舍,除了价值和优势之外,也带来一些需要去考虑的影响。
缺点
Part 02 架构与工程
从全局视角把握成果
微前端方案有哪些
-
使用 HTTP 服务器反向代理到多个应用
-
在不同的框架之上设计通讯、加载机制
-
通过组合多个独立应用、组件来构建一个单体应用
-
使用 iFrame 及自定义消息传递机制
-
使用纯 Web Components 构建应用
-
结合 Web Components 构建
微前端
每种方案都有自己的优劣,我们兄弟团队采用了最原始的网关转发配置类似 Nginx 配置反向代理,从接入层的角度来将系统组合,但是每一次新增和调整都需要在运维层面去配置。
而 iframe 嵌套是最简单和最快速的方案,但是 iframe的弊端也是无法避免的。
Web Components的方案则需要大量的改造成本。
组合式应用路由分发方案改造成本中等且满足大部分需求,也不影响个前端子应用的体验,是当时比较先进的一种方案。
架构设计选型注意点
-
如何降低系统的复杂度?
-
如何保障系统的可维护性?
-
如何保障系统的可拓展性?
-
如何保障系统的可用性?
-
如何保障系统的性能?
综合评估之后我们选用了组合式应用路由分发方案,但是仍然有架构整体蓝图和工程实现需要去设计。
需求分析
-
子应用独立运行/部署
-
中心控制加载(服务发现/服务注册)
-
子应用公用部分复用
-
规范子应用的接入
-
基座应用路由和容器管理
-
建立配套基础设施
设计原则
-
支持渐进式迁移,平滑过渡
-
拆分原则统一,尝试领域划分来解耦
应用架构图
应用架构图
系统拆分
系统拆分
这里拆分需要说明三个点:
-
独立部署(服务注册):上传应用资源包(打包生成文件)到Apollo配置平台,是一个点睛之笔
-
服务化和npm包插件化的区别是不需要通过父应用构建来集成,彼此依赖无关,发布独立,更加灵活/可靠
-
同时 Apollo 承载了注册中心的功能,可以省去子应用的web服务器的这一层,简化了架构
时序图
时序图
前端流程图
流程图
## Part 03 关键技术
落地中有哪些值得一提的技术细节
关键技术一览
我们按项目拆分来结构化讲述,有架构核心、注册中心、子应用、代码复用四篇。
其中包含了这些技术点:
-
Apollo
-
Apollo Cli
-
Version Manage
-
Sandbox
-
RouterMonitor
-
MicroPageLoader
-
Shared Menu
-
Shared Common
[架构核心]消息通信
消息通信
消息通信1
消息通信2
消息通信3
[架构核心]路由分发
路由分发
当浏览器的路径变化后,最先接受到这个变化的是基座的router,全部的路由变化由基座路由 RouterMonitor 掌管,因为它会去劫持所有引起url变化的操作,从而获取路由切换的时机。如果是apps/xxx/#
之前的变化,只会拦截阻止浏览器再次发起网页请求不会下发,没有涉及#之前的url变化就下发到子应用,让子应用路由接管。
[架构核心]应用隔离
主要分为 JavaScript执行环境隔离 和 CSS样式隔离。
JavaScript 执行环境隔离:每当子应用的JavaScript被加载并运行时,它的核心实际上是对全局对象 window 的修改以及一些全局事件的的改变,例如 JQuery 这个js运行之后,会在 window 上挂载一个 window.$ 对象,对于其他库 React、Vue 也不例外。为此,需要在加载和卸载每个子应用的同时,尽可能消除这种冲突和影响,最普遍的做法是采用沙箱机制 SandBox。
沙箱机制的核心是让局部的 JavaScript 运行时,对外部对象的访问和修改处在可控的范围内,即无论内部怎么运行,都不会影响外部的对象。通常在 Node.js 端可以采用 vm 模块,而对于浏览器,则需要结合 with 关键字和 window.Proxy 对象来实现浏览器端的沙箱。
CSS 样式隔离:当基座应用、子应用同屏渲染时,就可能会有一些样式相互污染,如果要彻底隔离 CSS 污染,可以采用 CSS Module 或者命名空间的方式,给每个子应用模块以特定前缀,即可保证不会相互干扰,可以采用 webpack 的 postcss 插件,在打包时添加特定的前缀。
对于子应用与子应用之间的CSS隔离就非常简单,在每次应用加载是,就将改应用所有的 link 和 style 内容进行标记。在应用卸载后,同步卸载页面上对应的 link 和 style 即可。
[架构核心]核心流程图
我们把路由分发、应用隔离、应用加载、通用业务逻辑收纳到到了微前端内核的二方包中,用作各个业务线复用,在内部达成统一约定。
内核流程图
[注册中心]Apollo
其实大部分公司在落地微前端方案的时候,并有没所谓的注册中心的概念。为什么我们的微前端也会有注册中心这个概念和实际存在呢?选型的思考点也主要来自我们后端的微服务架构。
注册中心
为什么选择引入注册中心增加整体架构的复杂度?
两个原因:
-
我们的子应用之间虽然不需要通信,但是也存在基座应用需要所有子应用的资源信息的情况,用来维护路由对应子应用资源地址的映射。大部分公司落地时候,都把子应用的地址信息硬编码到了基座。这样子应用增删改时候,就需要去重新部署基座应用,这违背了我们解耦的初衷。注册中心把这份映射文件从基座剥离出来了,让架构具备了更好的解耦和柔性。
-
要知道我们的子应用的产物入口是 hash 化的上传到 CDN 的 JS 文件,同时避免子应用发布也需要发布基座应用。有两个解决方案,一种是增加子应用的 Web 服务器,可以通过固定的 HTTP 服务地址拿到最新的静态资源文件。一种就是增加注册中心,子应用发布就是推送新的 JS地址给到 注册中心,子应用的架构就可以更薄。
需要一个注册中心的话,我们也有两种方案,一种是自己自研一个专门服务于自己的微前端,虽然可以更加贴合和聚焦,但是作为注册中心,高可用的技术底层要求下的熔断降级等机制必不可少,这些研发难度大成本也高。还有一种是直接应用成熟的提供注册中心能力的开源项目或者依赖公司的已经存在的技术设施组件。
最后我们确定在选用公司内部的基础技术设施的 Apollo 项目,优势有这么两方面。
-
项目本身开源,成熟程度很高,在多环境、即时性、版本管理、灰度发布、权限管理、开放API、支持端、简单部署等功能性方面做得很不错,是一个值得信赖的高可用的配置中心。
-
公司内部针对做了私有化定制和部署,更加适配业务,并且在 Java 和 Node 场景下都有稳定和使用,有维护人员值班。
apollo-basic
总结:
-
函数式编程其实是一种编程思想,它追求更细的粒度,将应用拆分成一组组极小的单元函数,组合调用操作数据流;
-
它提倡着 纯函数 / 函数复合 / 数据不可变, 谨慎对待函数内的 状态共享 / 依赖外部 / 副作用;
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
Tips:
其实我们很难也不需要在面试过程中去完美地阐述出整套思想,这里也只是浅尝辄止,一些个人理解而已。博主也是初级小菜鸟,停留在表面而已,只求对大家能有所帮助,轻喷🤣;
我个人觉得: 这些编程范式之间,其实并不矛盾,各有各的 优劣势。
理解和学习它们的理念与优势,合理地 设计融合,将优秀的软件编程思想用于提升我们应用;
所有设计思想,最终的目标一定是使我们的应用更加 解耦颗粒化、易拓展、易测试、高复用,开发更为高效和安全;