2023项目面试核心问题回答思路

184 阅读6分钟

说说你最近的项目

  • 记叙文六要素:时间、人物、地点、起因、经过、结果;
  • 时间:研发周期;
  • 人物:团队成员、分工、我负责那几个模块;
  • 起因:项目背景、项目的用户是谁、用户能用这个App干嘛、基本业务逻辑描述;
  • 经过:我负责哪几个模块,目前处于何种状态;
  • 结果:耗时多久上线、目前处于何种状态;
  • 项目亮点:最好有并且输出10分钟;

你负责哪几个模块?

  • 先下载一个业务及其相近的App在自己手机上;
  • 对着该蓝本App玩烂、充分脑补,而不是对着空气脑补;
  • 该蓝本App的各种菜单、导航、页面跳转按钮...就是所谓【模块】;
  • 信手一划拉就有十几个模块备选(不要来来回回就是登录、网络通信、路由跳转...)
  • 从以上几个模块中找几个你最能脑补出东西的模块来,号称是自己做的;

讲讲XX模块的实现细节

  • 业务功能是什么?事先玩透、脑补透;
  • 静态组件布局 + 网络通信获取数据 + 动态渲染 + 时间交互 + 后期优化;
  • 静态布局部分:核心组件,给核心组件传递的主要props与callback(组件与通信);
  • 网络通信:axios三层封装 + vuex/pinia/redux的数据缓存;
  • 事件交互:可能有基于antd/elementPlus的二次封装(初中级)、自定义组件库(中高级);
  • 后期优化:性能优化 + 复用提取(Vue和React如何复用逻辑);

为每个模块实现准备一些物料

  • 二次封装的组件若干(有明确的的名字与逻辑)
  • 自定义Hook若干
  • 自定义指令若干
  • HOC/RenderProp若干

有什么亮点?

  • 性能方面:性能方面:性能优化25条(简单:至少输出20分钟)
  • 复用方面:mixin、自定义指令、自定义hook、HOC、RenderProp、自定义组件(二次封装/自定义组件库)(略难:尽量准备)

有什么难点?

  • 不一而足,请为最近的两个项目各自准备一个难点;(至少输出20分钟)

怎么做优化?

  • 性能方面:性能优化25条(简单:至少输出20分钟)
  • 复用方面:mixin、自定义指令、自定义hook、HOC、RenderProp、自定义组件(二次封装/自定义组件库)(略难:尽量准备)

如何排查BUG?

  • 多打log(解决了记得清除)
  • 网络错误多看控制台中的网络项,善用其中的各种过滤器
  • 看报错信息,先看一下日志结构,迅速找到重点:例如错误id、代码行号等
  • 善用vscode的全局搜索功能,迅速定位关键词出现的位置
  • 多提交,这样可以利用版本回退定位bug发生的阶段
  • 依赖方面的错误,删除lock文件,删除node_modules,重新执行npm i试一下
  • 重启开发服务器、重启vscode、重启电脑
  • 百度、掘金、烂笔头
  • 实在搞不定就先搞别的,有时候做到后面会突然获得灵感

日常开发中遇到过哪些问题?

  1. 项目跑不起来,依赖有问题(特别是哭的版本兼容性问题);

    解决方案:删除依赖分析文件package.lock、node_modules,重新执行npm i

  2. JS项目拿TS重构,不知道原始入参的类型,前期可以先any,后期追源码;

  3. Git的公共文件,忌讳重名、移动位置、删除等操作;

  4. ......


命令行工具

  • node版本切换/源切换:nvm/nrm
  • mock数据:json-server,fast-mock
  • 兼容性检查:canluse + caniuse-cmd
npm install -g caniuse-cmd
caniuse fetch
  • 删除文件/文件及:rimraf
npm i -g rimraf
rimraf ./node_modules

从数据中过滤掉不需要的字段后形成JSON

const info = {
    name: 'qxy',
    age: 18,
    friends: ['tom','bob']
}

// 在info的地址中将age覆盖为undefined
Object.assign(info, {friends: undefined})

// JSON的特性:不识别undefined
console.log(JSON.stringify(info))

// 返回:{name:'qxy, age:18}

如何处理海量/大量数据?

  1. 前后端协同处理,让后端数据接口支持分页获取数据;
  2. 考虑手动缓存数据 + 重构服务端接口;
  3. 懒加载:Suspense + lazy;
  4. 长长的大列表,内存里永远只留3屏数据【当前屏】+【上一屏】+【下一屏】;上上屏/下下屏的数据直接设置为null等待垃圾回收器去缓存;有一个库叫做betterScroll实现了该逻辑;

白屏问题

  • 正常使用异步的话,就不会阻塞渲染
  • 本质上是渲染被阻塞了(数据没回来,数据量太大);
  • Nuxt/Next收评使用服务端渲染

首屏渲染优化

  • 代码层面

    • 组件库的按需引入
    • 路由的懒加载
    • 使用服务端SSR,直接由服务端返回渲染好的HTML
    • 事件防抖节流,减少事件处理次数
    • 减少DOM层级
    • 减少DOM渲染次数(批量渲染documentFragment,差量渲染Vue/React)
  • 通信层面

    • 缓存网络数据在localStorage里或vuex/pinia/redux里,减少请求次数
    • 小图片直接使用base64以减少网络请求次数
    • 使用HTTP协议的强援,服务端给更新频率低的数据一个较长的缓存时间
    • 从CDN或静态资源服务器去获取图片、js、css、图标字体等静态资源
  • 打包层面

    • 对图片进行物理压缩,如在线压缩工具TinyPNG
    • 打包时对HTML、CSS、JS进行压缩处理
    • 开启Gzip压缩
    • 合理分包,将第三方包、轮子包、业务代码包分开,这样在前端版本升级时,往往还需要更新业务代码包,而第三方包和轮子包由于内容未变导致hash未变,因此直接被服务端视为304,从而直接使用本地缓存;
    • 打包时开启Tree-Shaking,摇掉无用代码,减少包体积
    • 从HTML中抽离CSS文件,以便单独下载与缓存

小程序的微信授权流程(用微信账号登录自家服务器)

  • 在小程序端wx.login()得到登录码code
  • 小程序请求自家的登录接口,携带登录码code
  • 自家服务器请求微信服务器,使用appid + appSecret + code 换回 session_key与openid
  • 自家服务器将session_key与openid重新换算为自家的登录信息(如token)
  • 小程序在后续请求自家服务器的过程中都携带token,自家服务器就知道小程序已经登录过了

参考连接

image.png

前端权限控制

  • 登录成功后,服务端返回该用户的角色/权限
  • 可以将该角色/权限等级数据存储在全局(例如全局状态管理)
  • 路由层面A计划-动态生成路由表:根据该用户的等级动态添加它有权访问的路由(一旦用户访问自己无权访问的路由时命中404)
  • 路由层面B计划-路由守卫:使用路由守卫,当用户越权的路由时一脚踹到登录页
  • 界面层面A计划-条件渲染:根据用户的权限条件渲染它能访问的link、组件、具体元素
  • 界面层面B计划-封装:
    • vue中可以自定义指令如v-auth="3",当用户的等级不足3级时将该按钮disabled调或隐藏掉
    • React中可以使用HOC实现例如WithCustomAuth(MyButton,3)在返回JSX的时候使用条件渲染
    function withCUstomAuth(Com,level){
        function Parent(props){
            authFromRedux >= level
            ? <Com{...props} />
            : <a href="/login">登录</a>
        }
    }