美团、百度、阿里、网易

151 阅读17分钟

美团

  • 网路协议随便讲讲
  • 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区别

  1. 用途:
  • useCallback 用于创建记忆化的回调函数,主要用于防止函数在每次渲染时重新创建,适用于将回调函数传递给子组件时,以避免不必要的重新渲染。
  • useMemo 用于记忆化计算结果,主要用于防止在每次渲染时重新计算昂贵的计算结果,适用于计算成本较高的值。
  1. 返回值:
  • useCallback 返回一个记忆化的回调函数。
  • useMemo 返回一个记忆化的值,这个值是通过传入的回调函数计算得到的。
  1. 参数:
  • useCallback 接收两个参数,第一个是回调函数,第二个是依赖数组。当依赖数组中的值发生变化时,才会重新创建回调函数。
  • useMemo 接收两个参数,第一个是计算函数,第二个是依赖数组。当依赖数组中的值发生变化时,才会重新计算值。
  1. 示例:

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

执行时机:

  • 初始化(不管有没有依赖都执行)
  • 依赖更新
  • 销毁更新
    1. 组件卸载执行
    2. 依赖变化执行
  • 销毁四种场景
    1. 网络请求取消
    2. 清楚定时器
    3. 取消全局订阅事件
    4. 清理副作用

是不是所有的函数都需要用usecallbak,什么情况下用什么情况下不用

使用 useCallback 的情况:

  1. 将回调函数传递给子组件: 如果你将回调函数作为 prop 传递给子组件,并且这个回调函数依赖于组件的状态或属性,使用 useCallback 可以确保子组件在父组件重新渲染时不会不必要地重新渲染。

    const memoizedCallback = useCallback(() => {
      // 回调逻辑
    }, [/* dependencies */]);
    
    return <ChildComponent callback={memoizedCallback} />;
    
  2. 依赖于特定状态或属性的副作用逻辑: 如果你在 useEffect 中使用回调函数,且这个回调函数依赖于特定的状态或属性,可以使用 useCallback 作为 useEffect 的依赖项,以确保只有在依赖项变化时才重新执行。

    const memoizedCallback = useCallback(() => {
      // 副作用逻辑
    }, [/* dependencies */]);
    
    useEffect(() => {
      memoizedCallback();
    }, [memoizedCallback]);
    

不使用 useCallback 的情况:

  1. 函数无依赖: 如果一个函数完全独立于组件的状态和属性,而且不会导致组件的重新渲染,可能不需要使用 useCallback

    function simpleFunction() {
      // 无依赖逻辑
    }
    
  2. 仅在渲染期间使用的内联函数: 如果一个函数只在渲染期间使用,不需要被传递给子组件或在 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 函数。
  1. componentDidMount

    • useEffect 中不传递依赖数组,Effect 正文只会在组件挂载时执行一次,模拟了 componentDidMount
    useEffect(() => {
      // componentDidMount 相关逻辑
      return () => {
        // componentWillUnmount 相关清理逻辑
      };
    }, []);
    
  2. componentDidUpdate

    • useEffect 中传递了依赖数组,Effect 正文会在依赖项发生变化时执行,模拟了 componentDidUpdate
    useEffect(() => {
      // componentDidUpdate 相关逻辑
      return () => {
        // componentWillUnmount 相关清理逻辑
      };
    }, [/* 依赖项 */]);
    
  3. componentWillUnmount

    • Cleanup 函数的存在,用于在组件即将卸载时执行清理工作,模拟了 componentWillUnmount
    useEffect(() => {
      // componentDidMount 或 componentDidUpdate 相关逻辑
      return () => {
        // componentWillUnmount 相关清理逻辑
      };
    }, [/* 依赖项 */]);
    

浏览器机制详细讲讲

一、URL解析

这一步比较容易理解,在浏览器地址栏输入url后,浏览器会判断这个url的合法性 ,以及是否有可用缓存,如果判断是 url 则进行域名解析,如果不是 url ,则直接使用搜索引擎搜索

二、域名解析

输入 url 并点击确定访问后,第二步是进行DNS域名解析,如果输入的是 ip地址,则可以省略这一步,因为DNS域名解析,就是把域名解析成ip地址

域名系统(DNS): 域名系统是互联网的一项服务,是一个将域名和ip地址相互映射的分布式数据库。

机器只能识别ip地址,但是对于使用者来说,ip地址是不容易被记忆的,为了能够让人们更轻松的记住网站地址,于是就有了域名系统,每一个域名都有一个对应的ip地址

三、 检查浏览器是否有缓存

  1. 通过Cache-ControlExpires来检查是否命中强缓存,命中则直接取本地磁盘的html(状态码为200 from disk(or memory) cache,内存or磁盘);
  2. 如果没有命中强缓存,则会向服务器发起请求(先进行下一步的TCP连接),服务器通过EtagLast-Modify来与服务器确认返回的响应是否被更改(协商缓存),若无更改则返回状态码(304 Not Modified),浏览器取本地缓存;
  3. 若强缓存和协商缓存都没有命中则返回请求结果。

浏览器查看缓存,如果请求资源在缓存中并且新鲜,跳转到转码步骤

  1. 如果资源未缓存,发起新请求

  2. 如果已缓存,检验是否足够新鲜,足够新鲜直接提供给客户端,否则与服务器进行验证。

  3. 检验新鲜通常有两个HTTP头进行控制ExpiresCache-Control

    • HTTP1.0提供Expires,值为一个绝对时间表示缓存新鲜日期
    • HTTP1.1增加了Cache-Control: max-age=,值为以秒为单位的最大新鲜时间

四、建立TCP连接

三次握手

四次挥手

五、页面渲染

最后一步就是页面渲染了,这是一个很复杂的过程

  1. 解析HTML,并搭建DOM树 浏览器接收到 html 文件后将其解析成 DOM 树,这个解析从接收到 html 文件 的时候就已经开始了,并不是等到接收完成后才开始,解析的过程是自上而下,先解析当前节点的所有子节点,再解析兄弟节点及其子节点
  2. 解析CSS,并搭建样式树 浏览器将所有的css包括其自身的样式全部解析成样式树,解析的过程中会自动去掉浏览器不能识别的样式
  3. HTMLCSS结合,搭建Render树(渲染树) 将每个 HTML 节点与其对应的 CSS 样式结合,搭建 Render
  4. 根据渲染树计算布局 根据已经生成好的 Render 树 ,计算每个节点的颜色、尺寸及位置等信息
  5. 将元素绘制到页面上 将计算好的节点绘制到页面上,这个过程可能会产生 重绘 和 重排(回流),要尽量避免回流

重绘: 因为元素的颜色,字体等不改变尺寸及位置的样式改变而重新绘制,性能消耗较小

重排(回流): 因为元素的尺寸或位置改变而导致的重新绘制,这种可能会导致多处元素重新绘制,性能消耗较大

注意:

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:解析速度快、多路复用、首部压缩

为什么包体积减少,首屏速度提升

  1. 更小的文件传输时间: 较小的包体积意味着更少的数据需要从服务器传输到客户端。这减少了网络传输的时间,特别是在网络速度较慢的情况下,可以显著提升首屏加载速度。
  2. 更快的解析和执行时间: 较小的包通常意味着更少的代码需要被解析和执行。浏览器在接收到 JavaScript 文件时需要进行解析和执行,这个过程是单线程的,因此文件越小,解析执行的时间越短,页面就能更快地呈现。
  3. 更少的网络请求: 较小的包体积可能意味着更少的资源文件需要被请求。每个网络请求都会带来一些开销,包括 DNS 查询、建立连接等。减少网络请求的数量有助于加快页面加载速度。
  4. 更好的缓存效果: 较小的包更容易被浏览器缓存,因此当用户再次访问相同页面时,可能能够从缓存中快速加载,而无需重新下载。
  5. 减少不必要的代码执行: 包体积减小通常伴随着代码的精简,即去掉不必要的、冗余的代码。这有助于减少浏览器执行的工作量,提高性能。

综合考虑这些因素,减小包体积是优化网页性能的重要手段之一。在现代前端开发中,开发者通常会采用一系列的优化策略,比如代码拆分(Code Splitting)、懒加载、Tree Shaking 等,以减小包体积,提高页面加载性能。

第二次打开因为有了缓存,包体积还会对首屏加载 速度有优化吗

在第二次打开页面时,如果资源已经被浏览器缓存,那么确实在一定程度上减轻了对于网络传输的依赖,但包体积的大小仍然对整体性能有一些影响,尽管不像首次加载那样显著。

包体积的大小对第二次打开页面的影响包括:

  1. 解析和执行时间: 即使资源已经缓存,浏览器仍然需要解析和执行其中的代码。较小的包体积仍然能够带来更快的解析和执行时间,从而提高页面的反应速度。
  2. 缓存更新: 如果你更新了应用的代码或资源,浏览器可能会检测到缓存失效并重新请求新的资源。在这种情况下,如果新的资源包体积较小,更新的速度将更快。
  3. 缓存过期: 缓存的资源并非永久有效,而是根据设置的缓存策略(如 Cache-Control 头中的 max-age)过一段时间后会过期。过期后,浏览器会重新请求资源。在这个过程中,较小的包体积可以更快地重新下载和解析。

移动端生产环境如何debug

在移动端生产环境中进行调试通常需要使用一些特定的工具和技术,以确保在生产环境中检测和解决问题。以下是一些在移动端生产环境中进行调试的一般性方法:

  1. Chrome 开发者工具: 使用 Chrome 浏览器的开发者工具,可以通过 USB 连接移动设备进行调试。在 Chrome 中,打开 DevTools(F12 或右键点击页面元素并选择 "检查"),然后通过 DevTools 的"远程设备"选项连接到移动设备。这样你就可以查看控制台日志、网络请求、性能分析等。
  2. 移动设备调试工具: 一些浏览器如 Safari(iOS)和 Chrome(Android)提供了专门的移动设备调试工具。在 Safari 中,你可以通过 Preferences > Advanced 中的 "Show Develop menu in menu bar" 来启用 Develop 菜单,然后选择 "Enter Responsive Design Mode"。在 Chrome 中,可以通过 DevTools 的 "Toggle device toolbar" 来模拟移动设备。
  3. 日志和错误追踪服务: 使用服务如 Sentry、Bugsnag 等,可以实时监测和报告 JavaScript 错误。这有助于追踪在生产环境中发生的错误,并提供详细的错误报告和堆栈跟踪。
  4. 远程调试工具: 使用一些专门的远程调试工具,比如 Weinre 或 Vorlon.js,它们允许你在生产环境中远程调试页面,查看 DOM 结构、网络请求等。
  5. 性能分析: 使用浏览器的性能分析工具,如 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更新了什么

  • 算法:最长数字连续序列是多少