前言:小编最近约了一次前端的线下面试,面试官人特别好,而且问的内容也很全面,全程持续了一个多小时,所以小编想做一次记录和总结,有问题的地方欢迎各位掘友在评论区指点迷津谢谢。。。
1. 首先就是亘古不变的自我介绍环节啦,pass~~
2. 我看见你第一个项目上写的项目优化手段挺多的,那你是具体做了哪些手段使得小程序可以比较流畅地运行的
答:(这个面试官直接从项目入手,没有先问些八股文啥的,emmm,挺好的说实话,没有把重点放在考察一些概念层面的东西):静态资源压缩(字体文件、视频、模型(我这个项目是在小程序中结合three.js使用的,所以会有一些3D模型)、图片等,以及对图片格式进行适当转化,比如考虑将jpg等转化为pn、webp等同等质量条件下体积更小的图片格式)、使用精灵图(也有说法叫雪碧图 CSS sprites);合并http请求; 将静态资源存放在云端(比如微信云存储),通过接口调取资源数据,避免静态资源体积太大而超过主包或者分包的体积限制等; 代码优化上可以避免过多使用全局变量和闭包,及时清除定时器任务等。
3. 项目中的具体优化后得到的量化数据你是怎么得出来的
答:原生微信开发者工具有个performance面板,通过在网络条件等无关变量不变的情况下进行统计,多次测试并统计得到的较为符合实际的数据。
4. 你的资加载的进度条是怎么实现的
答:通过promise分别加载各个资源,并且收集promise的完成状态并结合自己的计算公式更新进度条,最后使用promise.all将所有的promise传进来,等待所有的资源均加载成功之后更新进度条为100%并跳转到主页面,如果当中有哪个资源加载失败就给予错误提示,并重新下载资源
追问:你确定promise.all是等待所有的promise的完成而不是获取到最快的promise的完成吗,他是一种等待机制还是一种赛跑机制呢?promise.all的最终态(fullfilled 或者 rejected)是由最快的promise的完成还是说是怎么样的呢?
答:(当时没反应过来,面试官应该是想知道我有没有理解promise.all以及它和promise.race的区别吧,下面简单说一下这两者吧):
`Promise.all` 和 `Promise.race` 是两种不同的方法,用于处理多个 Promise 对象的组合和竞争。
1. `Promise.all`:
- 接收一个 Promise 对象数组作为输入。
- 返回一个新的 Promise 对象,该 Promise 对象在数组中所有的 Promise 对象都变为 resolved 状态时才会变为 resolved 状态,是一种等待机制。
- 如果数组中任何一个 Promise 对象变为 rejected 状态,那么整个 `Promise.all` 调用将立即变为 rejected 状态。
- 返回的 Promise 对象的 resolved 值是一个由所有输入 Promise 对象的 resolved 值组成的数组,按照输入 Promise 对象数组的顺序排列。
2. `Promise.race`:
- 接收一个 Promise 对象数组作为输入。
- 返回一个新的 Promise 对象,该 Promise 对象在数组中的任何一个 Promise 对象变为 resolved 或 rejected 状态时就会变为对应的状态,是一种赛跑机制。
- 返回的 Promise 对象的状态和值与第一个完成(无论是 resolved 还是 rejected)的 Promise 对象相同。
区别总结如下:
- `Promise.all` 等待所有的 Promise 对象都变为 resolved 状态,然后返回一个包含所有 resolved 值的数组。如果有任何一个 Promise 对象变为 rejected 状态,整个 `Promise.all` 调用都会立即变为 rejected 状态。
- `Promise.race` 只要有一个 Promise 对象变为 resolved 或 rejected 状态,返回的 Promise 对象就会立即变为对应的状态。它只关心第一个完成的 Promise 对象,忽略其他的 Promise 对象。
追问:有没有特意使得某个资源下载失败测试过后面的逻辑呢?(因为我在上一个问题回答中有个矛盾,也就是我当时确实没反应过来promise.all是等待机制还是赛跑机制的了,所以面试官追问到了这个问题)
答:没有。。。
5. 说一下你实习的内容,你从中收获了什么,可以展开讲讲,围绕实习经历来就好了
答:介绍了参与的项目,使用的技术栈和个人的收获,pass~~
6. 有没有了解过websocket? 使用过吗?
答:(下面是结合网上的数据给出的答案,本人回答的主体意思和下面差不多,总结了一下术语放在下面了)
WebSocket 是一种在客户端和服务器之间建立持久化连接的通信协议。它通过在单个 TCP 连接上提供全双工通信,允许服务器主动向客户端推送数据,并支持客户端和服务器之间的双向实时通信。
相对于传统的 HTTP 协议,WebSocket 具有以下特点:
1. 双向通信:WebSocket 允许客户端和服务器之间实现双向通信,无需客户端发起请求,服务器可以主动推送数据给客户端。
2. 持久连接:WebSocket 连接在客户端和服务器之间建立后,保持持久性连接,不会像 HTTP 请求那样在每次通信后关闭连接,从而减少了连接建立和关闭的开销。
3. 较低的开销:WebSocket 使用更轻量级的消息头,减少了数据传输时的开销。此外,由于使用单个 TCP 连接,避免了多次握手和头部信息的重复发送。
4. 实时性:WebSocket 提供了更高的实时性,数据可以实时地从服务器推送到客户端,使得实时聊天、实时数据更新等应用成为可能。
WebSocket 协议通过在客户端和服务器之间建立握手协议来建立连接,然后通过发送消息帧来进行双向通信。客户端和服务器可以通过发送帧来交换数据,这些帧包含有序的数据片段。
追问:它是如何保持持久化连接的呢?
答:(我当时回答的是心跳机制,简单介绍了一下它的过程,但是我的回答有瑕疵,因为WebSocket 是通过心跳机制来维持连接的稳定性和活跃性,而不是用来保持持久化连接的。心跳是指定期发送的小型探测消息,用于检测连接是否仍然有效。):
WebSocket 使用了一种称为 "Upgrade" 的协议升级机制来建立持久化连接。下面是 WebSocket 建立持久化连接的简要步骤:
1. 客户端向服务器发起 WebSocket 连接请求。这个过程通常是通过执行 JavaScript 代码中的 `new WebSocket(url)` 来创建 WebSocket 对象。
2. 服务器收到连接请求后,进行协议升级处理。服务器检查请求头中的 "Upgrade" 字段是否为 "websocket",并验证其他必要的字段和安全性。
3. 如果协议升级验证成功,服务器发送响应,状态码为 101 Switching Protocols。响应头中包含 "Upgrade" 字段,值为 "websocket",以及其他必要的字段。
4. 客户端收到服务器的响应后,确认协议升级成功。此时,WebSocket 连接建立完成,客户端和服务器之间开始进行双向通信。
5. 建立的 WebSocket 连接保持持久化,客户端和服务器可以随时通过该连接进行实时的双向通信。
通过使用 Upgrade 协议升级机制,WebSocket 在 HTTP 协议的基础上建立了持久化连接。这种持久化连接允许服务器主动向客户端推送数据,而不需要客户端发起请求。相比于传统的 HTTP 请求-响应模式,WebSocket 提供了更高效、实时的双向通信能力。
7. react hook 和 vue hook 有没有都在封装后对比分析过? 封装一个hook的重点是什么?
React 和 Vue 都引入了类似的概念,即 React Hook 和 Vue Hook,用于在函数组件中添加状态管理和其他功能。下面是对 React Hook 和 Vue Hook 进行对比分析的一些关键点:
1. 哲学和设计理念:
- React Hook:React Hook 的设计目标是使函数组件具备类组件的能力,通过将状态逻辑从组件中提取出来并进行重用,使组件更简洁、可读性更高。
- Vue Hook:Vue Hook 的设计目标是将 Vue 组件的功能和逻辑进行解耦,使其更易于组合和复用,同时提供更好的开发体验。
2. 语法和用法:
- React Hook:React Hook 使用 `useState`、`useEffect`、`useContext` 等钩子函数的形式来实现状态管理、副作用处理和上下文访问等功能。
- Vue Hook:Vue Hook 使用 `ref`、`reactive`、`watch`、`provide` 等 API 来处理响应式数据、监听变化、共享状态等。
3. 数据响应性:
- React Hook:在 React 中,通过 `useState` 和 `useEffect` 等 Hook,可以轻松地管理和更新组件的状态,并在状态变化时重新渲染组件。
- Vue Hook:在 Vue 中,通过响应式的 `ref` 和 `reactive`,以及监听器 `watch` 和 `computed`,可以实现数据的响应性,当数据发生变化时,自动更新相关的组件。
4. 组件生命周期:
- React Hook:React Hook 的 `useEffect` 可以替代类组件中的生命周期方法,如 `componentDidMount`、`componentDidUpdate` 和 `componentWillUnmount` 等。
- Vue Hook:Vue Hook 的 `onMounted`、`onUpdated` 和 `onUnmounted` 等钩子函数用于替代 Vue 组件的生命周期方法。
5. 插件和扩展性:
- React Hook:React Hook 提供了一种简单的方式来创建自定义 Hook,使开发者能够将共享的逻辑抽象为可复用的 Hook,并与其他开发者共享。
- Vue Hook:Vue Hook 的设计支持使用插件来扩展功能,如使用 `provide` 和 `inject` 实现全局状态管理,或使用 `watch` 和 `provide/inject` 实现跨组件通信。
封装一个 Hook 的重点在于抽象和重用逻辑。关键点包括:
- 识别和提取重复的逻辑,将其抽象为一个独立的可复用函数。
- 通过参数和返回值,使 Hook 可以适应不同的场景和需求。
- 在 Hook 内部使用合适的 Hook 和 API,以实现所需的功能。
- 提供清晰的文档和示例,使其他开发者能够理解和正确使用该 Hook。
通过封装 Hook,可以将复杂的逻辑和状态管理进行抽象和封装,使组件更易于理解、测试和维护,并促进代码的复用和组合。
8. 跨域是什么,你是怎么解决的?后端可不可以指定某个源的数据请求?
答:
跨域(Cross-Origin)指的是在浏览器环境中,当一个网页的 JavaScript 代码向不同域名、不同端口或不同协议的资源发起网络请求时,会遇到一些安全限制。这是由于浏览器的同源策略(Same-Origin Policy)所导致的。同源策略要求网页只能访问与其来源相同的资源,防止恶意网站窃取用户数据或进行其他安全攻击。
解决开发环境和生产环境的跨域问题的方法有所不同:
在开发环境中,通常是在本地进行前端开发,而后端服务可能运行在不同的域名或端口上。以下是一些常见的解决跨域问题的方法:
1. 设置代理服务器:在开发环境中,可以通过设置一个代理服务器来转发请求,将前端请求代理到后端服务的域名和端口上。这样可以绕过浏览器的同源策略限制。
2. CORS(跨域资源共享):后端服务可以通过在响应头中添加特定的 CORS 头来允许跨域访问。常见的 CORS 头字段包括 `Access-Control-Allow-Origin`、`Access-Control-Allow-Methods`、`Access-Control-Allow-Headers` 等。
在生产环境中,由于存在安全风险,跨域访问需要谨慎处理。以下是一些常见的解决跨域问题的方法:
1. JSONP(JSON with Padding):JSONP 是一种利用 `<script>` 标签的跨域技术,通过动态创建 `<script>` 标签,将数据包装在一个回调函数中返回给前端。但 JSONP 只支持 GET 请求,并且存在一些安全风险。
2. CORS:与开发环境中相同,可以通过在后端服务中设置 CORS 头来允许跨域访问。可以根据具体需求配置允许访问的域名、请求方法和头部信息等。
3. 反向代理:在生产环境中,可以使用nginx进行反向代理来将前端请求转发到后端服务。通过配置代理服务器,可以实现跨域访问,并且更加灵活和安全。
9. vue2 和 vue3 响应式的区别?
答:
Vue2和Vue3在响应式系统上的主要区别体现在它们实现响应式数据跟踪和更新的机制上。以下是详细的区别点:
1. **实现方式**:
- Vue2:基于`Object.defineProperty`实现响应式系统。它会遍历对象的每个属性,并使用`Object.defineProperty`方法将其转换为getter和setter。这样,当访问或修改这些属性时,Vue能够捕获到这些操作并触发相应的更新。
- Vue3:则采用了基于JavaScript的`Proxy`对象来实现响应式系统。当一个普通JavaScript对象被传递给Vue的`data`选项时,Vue会将其转化为具有响应式特性的对象。
2. **对数组的处理**:
- Vue2:通过重写数组方法(如push, pop, shift, unshift, sort, reverse, splice)来实现对数组变更的拦截。这意味着只有调用这些方法时,Vue才能检测到数组的变化。
- Vue3:由于使用了`Proxy`,它可以更直接地拦截到数组的变化,包括通过索引直接修改数组元素。
3. **新增和删除属性**:
- Vue2:由于`Object.defineProperty`仅对已经存在的属性进行劫持,因此Vue2无法检测到对象新属性的添加或属性的删除。但Vue2提供了`Vue.set`和`Vue.delete`方法来手动添加和删除响应式属性。
- Vue3:由于使用了`Proxy`,它可以更直接地检测到对象属性的添加和删除。
10.js 与 es 的区别是什么?
答:
JS" 指的是 JavaScript,这是一种广泛用于网页开发的脚本语言。而 "ES" 是 "ECMAScript" 的缩写,ECMAScript 是 JavaScript 语言的国际标准。因此,JavaScript 和 ECMAScript 在本质上是相关的,但存在一些区别。
### JavaScript 和 ECMAScript 的主要区别:
1. **定义**:
- **JavaScript**:是一种具有函数优先的轻量级,解释型或即时编译型的编程语言。虽然它是作为开发Web页面的脚本语言而出名,但是它也被用到了很多非浏览器环境中,JavaScript基于原型编程、多范式的动态脚本语言,并且支持面向对象、命令式、声明式、函数式编程范式。
- **ECMAScript**:是 JavaScript 语言的国际标准,定义了语言的语法、类型、语句、关键字、保留字、操作符、对象等。
2. **范围**:
- JavaScript 包含了 ECMAScript 标准定义的所有内容,但同时还包含了一些额外的 API 和对象,如 DOM(文档对象模型)和 BOM(浏览器对象模型),这些 API 和对象主要用于操作浏览器和网页内容。
- ECMAScript 只定义了 JavaScript 的核心语法和类型,而不包含任何特定的 DOM 或 BOM API。
3. **用途**:
- JavaScript 主要用于 Web 开发,但也可以用于其他环境,如 Node.js(服务器端 JavaScript)。
- ECMAScript 标准本身并不直接用于开发,而是作为 JavaScript 引擎和工具链实现的基础。
11. es6出一个新特性之后你会不会去尝试一下?
答:我举例回答了没有es6的语法时的var定义的变量的局限性和函数的复杂性(this指向问题),有了es6语法之后,引入的let、const以及箭头函数的好处,再说明我在项目中的使用频率(高),还有一些杂七杂八的...pass~~
12. 假如公司现在给你一个vue2的项目,你会不会考虑把他转型到vue3?
13. 写一个插入排序:
function insertionSort(arr) {
for (let i = 1; i < arr.length; i++) {
let key = arr[i];
let j = i - 1;
while (j >= 0 && arr[j] > key) {
arr[j + 1] = arr[j];
j = j - 1;
}
arr[j + 1] = key;
}
return arr;
}
14.写一个快速排序:
function quickSort(arr) {
if (arr.length <= 1) {
return arr;
}
const mid = Math.floor(arr.length / 2);
const pivot = arr[mid];
const left = [];
const right = [];
for (let i = 0; i < arr.length; i++) {
if (i !== mid && arr[i] < pivot) {
left.push(arr[i]);
} else if (i !== mid && arr[i] > pivot) {
right.push(arr[i]);
}
}
return [...quickSort(left), pivot, ...quickSort(right)];
}
15. 反问:公司氛围、最近使用的技术栈、有无技术大牛可以带我做企业开发规范,学习一些进阶方面的知识
16. 接着就是通过大屏投影介绍公司内部的业务给我看,以及技术选取方案,决策过程等等,再说一遍,面试官真的超级无敌好!!!
17. 面试完当天大概三个小时后,HR 就私聊我说我挺合适的,问我最快什么时候可以到岗,但是我还没想好去不去......下面附几张在这家公司拍的照片(地点在珠江新城中心地段),记录一下我的第一次线下面试,我的感觉是企业环境挺不错的,但是好多哥哥姐姐在工作,我i人没敢拿起手机拍一张...


结语: 如果哪里小编回答的不好麻烦在评论区指点一下谢谢,大佬如果对小编有什么建议也可以说说哦,非常感谢!!!其实面试官问了我不少问题,奈何小编只记得上面这些了,主要是这个线下面试挺有压迫感的,面试完感觉整个人都栓栓的,呜呜呜...