美团
- 网路协议随便讲讲
- tcp和udp区别
- http各个版本有什么区别
- js事件循环流程
- vue2和vue3区别
- vue和react区别
- reactNavtive
- 性能优化
- 代码数组扁平化
百度
vue2或者vue3中提供的能力,哪些能力是提供给开发者进行代码复用的
vue提供的api,哪些能够封装给团队进行复用
react有没有minix
react确实没有官方提供Mixins的概念,但在React的历史中确实有过一些关于Mixins的实验性尝试。React曾经支持Mixin的形式,即通过createClass中的mixins属性。这允许开发者在组件中引入来自其他对象的方法和状态。
然而,由于Mixins带来的一些问题,比如命名冲突、难以理解和维护的代码,React在版本15中已经不再推荐使用Mixins,而是提倡使用其他模式,比如组件组合和高阶组件。在React版本16中,完全移除了createClass和Mixins的支持。
usecallback介绍一下和usememo区别
- 用途:
useCallback: 用于创建记忆化的回调函数,主要用于防止函数在每次渲染时重新创建,适用于将回调函数传递给子组件时,以避免不必要的重新渲染。useMemo: 用于记忆化计算结果,主要用于防止在每次渲染时重新计算昂贵的计算结果,适用于计算成本较高的值。
- 返回值:
useCallback: 返回一个记忆化的回调函数。useMemo: 返回一个记忆化的值,这个值是通过传入的回调函数计算得到的。
- 参数:
useCallback: 接收两个参数,第一个是回调函数,第二个是依赖数组。当依赖数组中的值发生变化时,才会重新创建回调函数。useMemo: 接收两个参数,第一个是计算函数,第二个是依赖数组。当依赖数组中的值发生变化时,才会重新计算值。
- 示例:
useCallback 示例:
import React, { useCallback, useState } from 'react';
function MyComponent() {
const [count, setCount] = useState(0);
const handleClick = useCallback(() => {
setCount(count + 1);
}, [count]);
return (
<div>
<p>Count: {count}</p>
<button onClick={handleClick}>Increment</button>
</div>
);
}
useMemo 示例:
import React, { useMemo, useState } from 'react';
function MyComponent() {
const [count, setCount] = useState(0);
const expensiveValue = useMemo(() => {
// 计算成本较高的值
return count * 2;
}, [count]);
return (
<div>
<p>Count: {count}</p>
<p>Expensive Value: {expensiveValue}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
防止重新渲染usecallback和另一个api搭配使用
介绍下useEffect
执行时机:
- 初始化(不管有没有依赖都执行)
- 依赖更新
- 销毁更新
- 组件卸载执行
- 依赖变化执行
- 销毁四种场景
- 网络请求取消
- 清楚定时器
- 取消全局订阅事件
- 清理副作用
是不是所有的函数都需要用usecallbak,什么情况下用什么情况下不用
使用 useCallback 的情况:
-
将回调函数传递给子组件: 如果你将回调函数作为 prop 传递给子组件,并且这个回调函数依赖于组件的状态或属性,使用
useCallback可以确保子组件在父组件重新渲染时不会不必要地重新渲染。const memoizedCallback = useCallback(() => { // 回调逻辑 }, [/* dependencies */]); return <ChildComponent callback={memoizedCallback} />; -
依赖于特定状态或属性的副作用逻辑: 如果你在
useEffect中使用回调函数,且这个回调函数依赖于特定的状态或属性,可以使用useCallback作为useEffect的依赖项,以确保只有在依赖项变化时才重新执行。const memoizedCallback = useCallback(() => { // 副作用逻辑 }, [/* dependencies */]); useEffect(() => { memoizedCallback(); }, [memoizedCallback]);
不使用 useCallback 的情况:
-
函数无依赖: 如果一个函数完全独立于组件的状态和属性,而且不会导致组件的重新渲染,可能不需要使用
useCallback。function simpleFunction() { // 无依赖逻辑 } -
仅在渲染期间使用的内联函数: 如果一个函数只在渲染期间使用,不需要被传递给子组件或在
useEffect中使用,可能不需要使用useCallback。function MyComponent() { const handleClick = () => { // 内联逻辑 }; return <button onClick={handleClick}>Click me</button>; }
useEffect第一个返回值是干什么用的,都可以模拟哪些声明周期
useEffect 的第一个返回值是一个清理函数(cleanup function),用于在组件销毁时执行清理工作。
useEffect(() => {
// Effect 正文
return () => {
// Cleanup 函数
};
}, [/* 依赖数组 */]);
- Effect 正文: 在这里可以执行副作用,比如订阅事件、数据获取、手动修改 DOM 等。
- Cleanup 函数: 在组件即将卸载时执行,用于清理副作用,比如取消订阅、清除计时器等。如果
useEffect中的依赖项发生变化,React 会在执行新的 Effect 正文前先执行上一个 Effect 的 Cleanup 函数。
-
componentDidMount:- 在
useEffect中不传递依赖数组,Effect 正文只会在组件挂载时执行一次,模拟了componentDidMount。
useEffect(() => { // componentDidMount 相关逻辑 return () => { // componentWillUnmount 相关清理逻辑 }; }, []); - 在
-
componentDidUpdate:- 在
useEffect中传递了依赖数组,Effect 正文会在依赖项发生变化时执行,模拟了componentDidUpdate。
useEffect(() => { // componentDidUpdate 相关逻辑 return () => { // componentWillUnmount 相关清理逻辑 }; }, [/* 依赖项 */]); - 在
-
componentWillUnmount:- Cleanup 函数的存在,用于在组件即将卸载时执行清理工作,模拟了
componentWillUnmount。
useEffect(() => { // componentDidMount 或 componentDidUpdate 相关逻辑 return () => { // componentWillUnmount 相关清理逻辑 }; }, [/* 依赖项 */]); - Cleanup 函数的存在,用于在组件即将卸载时执行清理工作,模拟了
浏览器机制详细讲讲
一、URL解析
这一步比较容易理解,在浏览器地址栏输入url后,浏览器会判断这个url的合法性 ,以及是否有可用缓存,如果判断是 url 则进行域名解析,如果不是 url ,则直接使用搜索引擎搜索
二、域名解析
输入 url 并点击确定访问后,第二步是进行DNS域名解析,如果输入的是 ip地址,则可以省略这一步,因为DNS域名解析,就是把域名解析成ip地址
域名系统(DNS): 域名系统是互联网的一项服务,是一个将域名和ip地址相互映射的分布式数据库。
机器只能识别ip地址,但是对于使用者来说,ip地址是不容易被记忆的,为了能够让人们更轻松的记住网站地址,于是就有了域名系统,每一个域名都有一个对应的ip地址
三、 检查浏览器是否有缓存
- 通过
Cache-Control和Expires来检查是否命中强缓存,命中则直接取本地磁盘的html(状态码为200 from disk(or memory) cache,内存or磁盘); - 如果没有命中强缓存,则会向服务器发起请求(先进行下一步的TCP连接),服务器通过
Etag和Last-Modify来与服务器确认返回的响应是否被更改(协商缓存),若无更改则返回状态码(304 Not Modified),浏览器取本地缓存; - 若强缓存和协商缓存都没有命中则返回请求结果。
浏览器查看缓存,如果请求资源在缓存中并且新鲜,跳转到转码步骤
-
如果资源未缓存,发起新请求
-
如果已缓存,检验是否足够新鲜,足够新鲜直接提供给客户端,否则与服务器进行验证。
-
检验新鲜通常有两个HTTP头进行控制
Expires和Cache-Control:HTTP1.0提供Expires,值为一个绝对时间表示缓存新鲜日期HTTP1.1增加了Cache-Control: max-age=,值为以秒为单位的最大新鲜时间
四、建立TCP连接
三次握手
四次挥手
五、页面渲染
最后一步就是页面渲染了,这是一个很复杂的过程
- 解析
HTML,并搭建DOM树 浏览器接收到html文件后将其解析成DOM树,这个解析从接收到html文件 的时候就已经开始了,并不是等到接收完成后才开始,解析的过程是自上而下,先解析当前节点的所有子节点,再解析兄弟节点及其子节点 - 解析
CSS,并搭建样式树 浏览器将所有的css包括其自身的样式全部解析成样式树,解析的过程中会自动去掉浏览器不能识别的样式 - 将
HTML和CSS结合,搭建Render树(渲染树) 将每个HTML节点与其对应的CSS样式结合,搭建Render树 - 根据渲染树计算布局 根据已经生成好的
Render树 ,计算每个节点的颜色、尺寸及位置等信息 - 将元素绘制到页面上 将计算好的节点绘制到页面上,这个过程可能会产生 重绘 和 重排(回流),要尽量避免回流
重绘: 因为元素的颜色,字体等不改变尺寸及位置的样式改变而重新绘制,性能消耗较小
重排(回流): 因为元素的尺寸或位置改变而导致的重新绘制,这种可能会导致多处元素重新绘制,性能消耗较大
注意:
CSS 不会阻塞 DOM 树 的搭建,但是会阻塞页面的渲染,这是因为页面渲染需要先计算好节点的样式 HTML 文件中的外部资源会提前加载,不会等到渲染完成后再加载 JS 会阻塞 HTML 的解析,因为浏览器不知道 JS 脚本的内容,但JS脚本有可能会操作DOM,为了避免重复渲染,浏览器会先加载 JS 脚本 CSS 会阻塞 JS 的执行,因此需要将 <script> 标签放在 <link> 标签之前
浏览器事件循环
. 任务队列(Task Queue):
- 事件循环通过任务队列来管理待执行的任务。任务可以是同步任务(立即执行)或异步任务(稍后执行)。
2. 宏任务(Macro Task)和微任务(Micro Task):
- 浏览器将任务划分为宏任务和微任务。常见的宏任务包括整体的 script 代码、setTimeout、setInterval 等。微任务包括 Promise 的 then 方法和 MutationObserver。
3. 执行栈(Call Stack):
- 执行栈用于管理 JavaScript 代码的执行。同步任务会直接进入执行栈,而异步任务会被放入任务队列等待执行。
4. 事件循环的阶段(Event Loop Phases):
- 同步执行阶段: 执行栈中的同步任务会被依次执行。
- 宏任务执行阶段: 从宏任务队列中选择一个宏任务执行,执行完毕后检查是否有微任务。
- 微任务执行阶段: 执行微任务队列中的所有微任务。
- 回到宏任务执行阶段: 循环执行宏任务和微任务,直至任务队列为空。
node事件循环
Node.js中宏任务分成了几种类型,并且放在了不同的task queue(事件队列)里。不同的task queue在执行顺序上也有区别,微任务放在了每个task queue的末尾:
setTimeout/setInterval属于 timers 类型;setImmediate属于 check 类型;- socket 的 close 事件属于 close callbacks 类型;
- 其他 MacroTask 都属于 poll 类型。
process.nextTick本质上属于 MicroTask,但是它先于所有其他 MicroTask 执行;- 所有 MicroTask 的执行时机在不同类型的 MacroTask 切换后。
- idle/prepare 仅供内部调用,我们可以忽略。
- pending callbacks 不太常见,我们也可以忽略。
首屏加载速度怎么统计的,时间起点和终点的api什么
// 使用 Navigation Timing API 获取首屏加载时间
window.addEventListener('load', function() {
const navigationStart = performance.timing.navigationStart;
const loadEventEnd = performance.timing.loadEventEnd;
const firstPaintTime = loadEventEnd - navigationStart;
console.log('首屏加载时间(毫秒):', firstPaintTime);
});
-
首屏加载时间First Contentful Paint(FCP) :首次内容绘制时间,指浏览器首次绘制页面中至少一个文本、图像、非白色背景色的
canvas/svg元素等的时间,代表页面首屏加载的时间点。 -
首次绘制时间First Paint(FP) :首次绘制时间,指浏览器首次在屏幕上渲染像素的时间,代表页面开始渲染的时间点。
-
最大内容绘制时间Largest Contentful Paint(LCP) :最大内容绘制时间,指页面上最大的可见元素(文本、图像、视频等)绘制完成的时间,代表用户视觉上感知到页面加载完成的时间点。
-
用户可交互时间Time to Interactive(TTI) :可交互时间,指页面加载完成并且用户能够与页面进行交互的时间,代表用户可以开始操作页面的时间点。
-
页面总阻塞时间Total Blocking Time (TBT) :页面上出现阻塞的时间,指在页面变得完全交互之前,用户与页面上的元素交互时出现阻塞的时间。TBT应该尽可能小,通常应该在300毫秒以内。
-
搜索引擎优化Search Engine Optimization (SEO) :网站在搜索引擎中的排名和可见性。评分范围从0到100,100分表示网站符合所有SEO最佳实践。
首屏加载事件优化做了哪些处理
- webpack的tree shaking、slit chunks
- Nginx配置的gzip压缩
- 图片(压缩、分割、雪碧图、懒加载、格式webp、svg、小图base64)
- cdn
- 代码算法降低复杂度:节流防抖、v-if、v-for、路由懒加载、打包去掉map文件、UI库懒加载
- web worker创造多线程环境、允许主线程创建 Worker 线程,将一些任务分配给后者运行。在主线程运行的同时, Worker 线程在后台运行,两者互不干扰。等到 Worker 线程完成计算任务,再把结果返回给主线程
- 利用缓存:浏览器缓存、CDN、本地缓存、分布式缓存、数据库缓存。
- SSR
- HTTP2:解析速度快、多路复用、首部压缩
为什么包体积减少,首屏速度提升
- 更小的文件传输时间: 较小的包体积意味着更少的数据需要从服务器传输到客户端。这减少了网络传输的时间,特别是在网络速度较慢的情况下,可以显著提升首屏加载速度。
- 更快的解析和执行时间: 较小的包通常意味着更少的代码需要被解析和执行。浏览器在接收到 JavaScript 文件时需要进行解析和执行,这个过程是单线程的,因此文件越小,解析执行的时间越短,页面就能更快地呈现。
- 更少的网络请求: 较小的包体积可能意味着更少的资源文件需要被请求。每个网络请求都会带来一些开销,包括 DNS 查询、建立连接等。减少网络请求的数量有助于加快页面加载速度。
- 更好的缓存效果: 较小的包更容易被浏览器缓存,因此当用户再次访问相同页面时,可能能够从缓存中快速加载,而无需重新下载。
- 减少不必要的代码执行: 包体积减小通常伴随着代码的精简,即去掉不必要的、冗余的代码。这有助于减少浏览器执行的工作量,提高性能。
综合考虑这些因素,减小包体积是优化网页性能的重要手段之一。在现代前端开发中,开发者通常会采用一系列的优化策略,比如代码拆分(Code Splitting)、懒加载、Tree Shaking 等,以减小包体积,提高页面加载性能。
第二次打开因为有了缓存,包体积还会对首屏加载 速度有优化吗
在第二次打开页面时,如果资源已经被浏览器缓存,那么确实在一定程度上减轻了对于网络传输的依赖,但包体积的大小仍然对整体性能有一些影响,尽管不像首次加载那样显著。
包体积的大小对第二次打开页面的影响包括:
- 解析和执行时间: 即使资源已经缓存,浏览器仍然需要解析和执行其中的代码。较小的包体积仍然能够带来更快的解析和执行时间,从而提高页面的反应速度。
- 缓存更新: 如果你更新了应用的代码或资源,浏览器可能会检测到缓存失效并重新请求新的资源。在这种情况下,如果新的资源包体积较小,更新的速度将更快。
- 缓存过期: 缓存的资源并非永久有效,而是根据设置的缓存策略(如 Cache-Control 头中的 max-age)过一段时间后会过期。过期后,浏览器会重新请求资源。在这个过程中,较小的包体积可以更快地重新下载和解析。
移动端生产环境如何debug
在移动端生产环境中进行调试通常需要使用一些特定的工具和技术,以确保在生产环境中检测和解决问题。以下是一些在移动端生产环境中进行调试的一般性方法:
- Chrome 开发者工具: 使用 Chrome 浏览器的开发者工具,可以通过 USB 连接移动设备进行调试。在 Chrome 中,打开 DevTools(F12 或右键点击页面元素并选择 "检查"),然后通过 DevTools 的"远程设备"选项连接到移动设备。这样你就可以查看控制台日志、网络请求、性能分析等。
- 移动设备调试工具: 一些浏览器如 Safari(iOS)和 Chrome(Android)提供了专门的移动设备调试工具。在 Safari 中,你可以通过 Preferences > Advanced 中的 "Show Develop menu in menu bar" 来启用 Develop 菜单,然后选择 "Enter Responsive Design Mode"。在 Chrome 中,可以通过 DevTools 的 "Toggle device toolbar" 来模拟移动设备。
- 日志和错误追踪服务: 使用服务如 Sentry、Bugsnag 等,可以实时监测和报告 JavaScript 错误。这有助于追踪在生产环境中发生的错误,并提供详细的错误报告和堆栈跟踪。
- 远程调试工具: 使用一些专门的远程调试工具,比如 Weinre 或 Vorlon.js,它们允许你在生产环境中远程调试页面,查看 DOM 结构、网络请求等。
- 性能分析: 使用浏览器的性能分析工具,如 Chrome 的 Performance 面板,来检查页面的性能瓶颈。这有助于了解页面加载和运行时的性能问题。
阿里
- 分别用xss和csrf模拟黑客进行攻击
- 给出一段正则表达式,说出意思
- 实现节流函数
- vue和react修改当前组件的css怎么做的,原理是什么
- vue2,3对比,react对比
- 如何对比dom节点
- 用纯css实现一个elementUI的组件
- 介绍下浏览器缓存
- 写一个数组,1-100,然后乱序输出
异乡好居
- vue和react中的key有什么作用
- vue2和vue3的劫持绑定,有什么区别
- proxy底层是否也是循环去遍历对象
- 对proxy的懒劫持怎么看
- 做过哪些性能优化
- 用什么工具或者指标去看性能的优化
- webpack中的loading和plugin有什么区别,可以互相替代吗
- 自己写过loader和plugin
- vue的ssr中接口会请求几遍,在哪里请求
网易
一面
- 如何做路由的限制,如何鉴权
- 为什么用webworker
- 大屏适配使用的什么方案
- 介绍一下常用的hooks
- 子组件的方法如何暴露给父组件(useImperativeHandle)
- vuex原理和使用
- 如何持久化vuex存储的市值
- vue的watch和computed
- 介绍下ssr,相对于csr有什么优势
- 如何进行文件上传
- 银行和私企有什么区别
- 在任务活比较急的话如何沟通
- 介绍下react的fiber架构
- 怎么理解单项数据流
- 介绍一个flex布局
- 垂直水平居中的几种方法
- 介绍一下js闭包
- 介绍了vuex和pinia
- 算法:输入重复项的index最小值
二面
-
为什么两个后台的技术栈
-
介绍下会议的webrtc
-
介绍下单点登录
-
小程序用的是什么框架,为什么选择uniapp
-
h5兼容会遇到什么问题
-
小程序下面的按钮不想显示怎么做
-
对于不同屏幕的解决方案是什么
-
rem如何设置的,原理是什么
-
eventloop
-
节流防抖,原理和应用
-
介绍下BFC,如何设置
-
常用的hooks
-
usEeffect中的return是干什么用的
-
useMemo套一个子组件的作用是什么
-
useRef的作用,const abc=useRef,防刷新
-
介绍下react,fiber架构
-
react18更新了什么
-
算法:最长数字连续序列是多少