HLJ一面

232 阅读13分钟

自我介绍

1. 有参与过脚手架的维护吗?

没有。

2. 是怎么去做 codeReview 的?比较注重哪些点?

主要注重编码规范,健壮性检查,质量保证,统一风格,完善注释。

保证代码的可读性,一致性,提升代码质量。

3. 在做视觉稿管理系统的时候,有什么比较印象深刻的有难度的地方吗?

切换主题的设计:使用less,将不同主题的颜色变量写在不同的样式文件中,使用 less-vars-to-js 将各个文件的颜色变量转为js对象, 使用 less.modifyvars 在点击切换主题时进行变量替换。 在 react 中用 less 动态切换主题样式 使用 css/less 动态更换主题色(换肤功能)

消息中心的设计:

因为负责视觉稿管理系统的后端的整体架构和实现,全面的对于后端有了更深刻的理解,让我在数据库建表,前端技术方面有了更大的进步。考虑到消息中心中有两种消息通知,一种是点对点,因为用户操作而产生的通知,一种是系统给全体用户发送的公告,还需要有已读未读的功能,所以新建了两张表,notify_event 存储单条通知,notify_remind 存储单次通知的关联id,发送者、接收者和是否已读等数据。在通知实现方面,考虑到通知的实时性需求不强,采用了间隔5分钟的轮询的方式实现。此外,上传视觉稿或更新视觉稿时,还会通过钉钉群推送的方式通知到该项目相关成员。

部署遇到的工具冲突的问题:

我在这个项目中主要负责Node后端,使用了TS + Egg框架,为了能够实现接口文档在线化,用到了一个通过 Controller 里的注释自动生成接口文档的工具包:egg-swagger-doc-feat。在开发期间,egg-loader 会自动加载 *.ts 并内存编译。此时运行是没有问题的,但在部署时,会将 ts 构建为 js,发现egg-swagger-doc-feat就会报错,Controller 不存在

刚开始出现这个问题,我就去网络上找答案,但是发现很少有人出现这个问题,去看issue的时候有找到类似问题的答案,但是发现并不适用于我的情况。于是只能通过源码去寻找,发现这个插件有针对 ts 和 js 做相应的优化,在获取controller的时候,做了一个判断,如果是ts文件,就去获取default, 如果是js则直接获取。

if (path.extname(filepath) === '.ts') {
    obj = obj.default;
  }

当时我们ts文件是这样写的:

export default class DemandController extends Controller {
}

所以能够获取到,但是当运行 npm run tsc 命令将ts转成js后,exports.default = DemandController; 还是存在default,导致获取不到内容,继而后续报错。

发现问题以后我的第一想法是,考虑如何修改自己的代码,去兼容这个工具包:换成 module.exports 的写法,是否可以呢?结果还是不行,因为这样在ts模式下就获取不到内容了。所以最终我是通过将工具包的源码down下来,把它对ts做特殊处理的这一段代码删掉,在公司内部发了一个二方包,解决了这个问题。

光敏:全面的对于后端有了更深刻的理解,如何设计接口,如何设计字段,比如考虑到xx情况,减少了性能开销,对整个项目进行了分析,面向的对象是谁,架构,做的过程中发现了xx问题,优化。复盘过程中解决了什么

4. Node 的基本原理有了解吗?

Node具有异步I/O,事件驱动,单线程等特点。

异步I/O: 类似于前端中的 Ajax 请求,异步代码会在同步代码执行完成后,等待异步返回结果再执行,在Node中,绝大多数操作都是以异步的方式进行调用,从文件读取到网络请求等,好处是,每个调用无需等待之前的I/O调用结束。而同步I/O需要等待前一个I/O调用结束后才能够开始。

事件驱动:通过事件队列,回调函数队列完成任务调度。

单线程:Node中js代码的执行是单线程的。无需像多线程语言处理状态同步问题,也省去了切换线程上下文带来的性能开销。缺点是无法利用多核cpu,错误会引起整个应用的退出,健壮性较差。大量计算会占用CPU导致无法调用异步I/O。

5. Node 的DNS模块,HTTP模块有了解吗?I/O事件模型?

dns和http不了解,I/O 同上。

6. 体现设计能力的一些点?架构上,或某一个功能的设计上?扩展性,稳定性,鲁棒性?

业务场景,用户体验,

业务项目策略中心中,包括标签中心,模型中心,任务中心,其中一个任务对应多个标签和一个模型,用户可以在任务中心中新建、编辑标签和模型,所以在前端模块设计的时候,就将标签和模型的新建页面提取成两个组件。复用在标签、模型、任务中心中。

鲁棒性方面,使用了lodash、解构默认值,try-catch 等方式,来减少读取变量出现的错误;通过例如点击提交按钮后及时将按钮置为loading等方式,来防止用户多次点击。

7. 怎么去做到了支撑快节奏的开发需求?比如说因为设计的比较好,效率比较高?

选择了TS作为开发语言,帮助前端开发者尽快的推断变量类型,提升代码可读性。

8. TS 是你引入的吗?当时是怎么考虑的,做了什么调研?

  1. TypeScript提供了一种编译阶段的类型系统,在代码提示,错误检测,代码生成及格式化方面答复提高开发效率。
  2. 丰富的类型,能够帮助开发者尽快推断变量,参数,返回值的类型,提升代码可读性,减少依赖逻辑代码的阅读,将注意力更多的放在功能的具体实现上。

9. 使用TS的话,会对后端获取到的数据类型进行转化吗?还是只是用了interface做了一个类型的标明?

没有做类型转化,做了类型标明。

10. 之前写过Java吗?蓝桥杯。

写过。

11. Java 的面向对象?

封装、继承、多态。

java中对类的属性进行了封装,分为公有和私有。目的是为了保护信息。继承是指子类可以通过继承来获得父类的所有特征和行为。多态是指父类中拥有的属性和行为,在子类继承后可以有不同的表现形式。子类可以在父类的基础上新增属性或行为,或者对于父类的行为进行重载或重写。

12. JS是否是一个面向对象的语言?

类。Object。protoType。

js是基于原型的(prototype),我们能接触到的都是对象。我们也可以通过构造函数,call,apply,bind等方式实现封装,继承,多态。

13. React Hooks 配合 TS 用,React.FC 用过吗?

React.FC是函数式组件,是在TypeScript使用的一个泛型。

14. React 配合 TS 用到 泛型?

泛型就是将所操作的数据类型指定为一个参数,这个参数可以用于类,接口和方法的创建中。

因为ts不建议使用any,不能保证类型安全,调试时缺乏完整的信息,当我们有可重用的组件时,可以使用泛型,它可以支持当前数据类型,也可以支持未来的数据类型,扩展灵活,能够保证类型安全。

15. setState时,一个父组件有两个子组件,父子组件的componentShouldUpdate,和 componentDidUpdate 这两个生命周期的执行顺序是怎样的?

先进行父组件的componentShouldUpdate,两个子组件的componentShouldUpdate,再进行两个子组件的componentDidUpdate,再进行父组件的 componentDidUpdate。

16. PureComponent 是做什么的?

表示一个纯组件,他其实是在componentShouldUpdate时帮助我们对state和props进行了一个浅比较,它可以优化程序,减少渲染次数,提高性能。

17. 如果传给 PureComponent 的是个对象呢?它会深比较还是浅比较?

浅比较,比较的是地址。

18. 为什么是浅比较?

出于对性能的考虑。在生命周期中去递归比较对象是十分消耗性能的。

19. state={ value: 1 }; this.state.value = 100; 然后 this.setState(this.state); 页面会发生渲染吗?

会。

20. 上面这样写会有什么问题?

这种直接改变原有对象的方式导致react无法对其进行任何优化,因此会有潜在的性能问题;如果你用了 PureComponent, 会发现状态无法直接更新。原因在于 PureComponent 重写了 shouldComponentUpdate,shouldComponentUpdate 中通过直接判断 state 和 props 前后的引用差别来判断,因此会返回false,导致render无法运行。

21. React 的原理,有去了解过吗,委托,fiber?

委托: React在管理事件绑定时,不是将事件直接绑定在DOM上的,而是将事件都绑定在document上,通过合成事件进行委托管理。当事件发生的时候,都冒泡到document上, react再通过document去统一分发事件。(在事件管理中心存储所有的dom事件,document作为事件委托者,通过dom的唯一标识,在事件管理中心触发事件) 比如我们平时用的e.stopPropogation,是React对于原生事件的封装。而原生事件需要通过e.nativeEvent.xx 获取。 目的是 消除浏览器差异带来的影响,通过委托给document也节约了内存。但是,在React 17 中,React 更改了事件委托,将事件委托到了根节点上,让react的事件树更符合dom规范。 事件委托

fiber: React 15 之前,虚拟dom的diff操作是同步完成的,当页面有大量dom节点时,diff时间可能会过长,造成卡顿。为了解决这个问题,react 推出了fiber,将任务进行分片,每执行完一段更新过程,就把控制权交给任务协调模块,如果有紧急任务(用户操作等),就去执行紧急任务,没有则继续更新。 image.png

22. this.setState 调用了两次,会渲染两次吗?

不会。

23. setState的第二个参数成功的回调函数,是同步的还是异步的?是在DOM渲染之前回调,还是DOM渲染之后回调?是宏任务还是微任务?有去了解过吗?或者是怎么推测分析出来的?

异步的,DOM渲染之后回调,=============暂未解决=================================

24. 微任务和宏任务的执行关系是什么样子的?

js中有个机制叫事件循环,因为js引擎在执行js代码的时候会产生执行栈,我们的同步代码都会放入执行栈中执行,当遇到异步任务的时候,会将异步任务放至该同步任务的任务队列中,当同步任务执行完成,就去查看任务队列中是否有要执行的异步任务,依次将其放入执行栈中执行。 宏任务包括script,setTimeout,setTimeInterval,setImmidate,I/O,rendering等。微任务主要是 Promise。 通过一系列的实验,我们可以总结一下如何分析异步执行的顺序:

  1. 首先我们分析有多少个宏任务;
  2. 在每个宏任务中,分析有多少个微任务;
  3. 根据调用次序,确定宏任务中的微任务执行次序;
  4. 根据宏任务的触发规则和调用次序,确定宏任务的执行次序;
  5. 确定整个顺序。

25. useCallback 和 useMemo 用过吗?

useCallback 用于缓存函数,比如,当函数作为props传递给子组件时,如果父组件更新,函数会被重新创建,导致子组件中有依赖于该函数的 uesEffect 也会被重新调用。

useMemo 用于缓存值,其在 react hooks 中的作用有些类似于PureComponent。

26. useCallback 在 React 中实际的作用是什么?

27. useEffect 第二个参数是空数组的时候,在里面启动了一个 setInterval,去调用了一个state,但是当外界的state改变的时候,setInterval 里用的值是新的还是旧的?

旧的。

28. React 里因为什么会导致这个问题?

闭包?react 中的思想是将render的每一次看做一个帧,而每一个帧都对应一个useEffect。

29. 通用业务模板库的提效数据是如何计算的?

30. 组件库是怎么去进行编译的?babel 基于 webpack,支持按需加载吗?怎么做到的?

babel-plugin-import,解析成 AST 树,import {Button} from 'antd' => import Button from 'antd/bin/button'。

31. 组件库的 button webpack 是怎么打成单个文件的?

32. 讲一下你设计的比较好的一个组件?

其实一个组件设计的好的时候,字段的命名在很大程度上就能够给大家带来一个比较好的使用感受,某些字段封装的好的话也能更清楚,设计也是很重要的。

cy的评级?

为什么想离职?

不怎么追逐技术,希望能够技术上有更多的成长。

al内部的很完善的东西,比开源出来的东西更强大,你有去学习了解过或者钻研过吗?

除了工作中用到的东西,有自己额外了解学习的东西吗?或者比较感兴趣的?

你期望加入的团队能给你带来什么?

技术氛围浓,有挑战的事情

有什么问题想问我?

对我的评价,后续的建议?

虽然现在推动了团队用react hooks,ts,但自己用的并不熟,有种头重脚轻的感觉。自己做了组件库的一些东西,要想一想如何更好地去表达,感觉上你对于偏软的方面可能更擅长,比如设计,CR,代码,沟通协调比较强,在面试过程中这个东西如何去展示,比如我问了你之前做了什么东西,你想了半天没有想出来。在React方面文档还可以再看一下,系统的学习一下。很多东西是零散的一个经验,自己串不起来,可以串起来形成一个体系。

业务:app、商家后台、官网、金鸡奖小程序、CRM。react 的脚手架,业务组件库和基础组件库,构建,TS,文档,性能等都可以优化,SSR的优化,监控系统。

项目亮点

这样介绍自己的项目经验,面试成功率能达到98.99%