前端面试题详解整理35| http2.0useCallback的缓存 Hooks304请求响应过程协商缓存,useCallback快排算法,Hooks怎么工作,

46 阅读12分钟

阿里灵犀互娱前端一面凉经

可能因为没有笔试,先做了一个小时题目,4道题,一道没a出来,讲了思路

1、 http 304响应码,以及请求响应过程

HTTP 304是HTTP状态码之一,表示“未修改”(Not Modified)。当客户端发送一个条件GET请求(通常是带有If-Modified-Since或If-None-Match头部)给服务器,而服务器判断所请求的资源自上次请求后并未发生改变时,就会返回HTTP 304响应码。

下面是HTTP 304响应的请求-响应过程:

  1. 客户端发送请求: 客户端发送一个GET请求给服务器,请求某个特定的资源。

  2. 服务器收到请求: 服务器收到客户端的请求,并解析其中的信息,包括所请求的资源。

  3. 服务器判断资源是否修改: 服务器检查所请求的资源的修改时间或标识(通常是与之前请求时保存的Etag或Last-Modified头部值进行比较),来确定该资源是否自上次请求以来发生了变化。

  4. 资源未修改: 如果服务器判断所请求的资源自上次请求以来未发生修改,则服务器不会返回资源的内容,而是发送HTTP 304响应码给客户端。

  5. 客户端接收响应: 客户端收到服务器返回的HTTP 304响应码后,会根据缓存策略来处理这个响应。通常情况下,客户端会从本地缓存中加载资源,而不会重新从服务器下载。

  6. 结束请求-响应过程: 请求-响应过程结束,客户端可以使用本地缓存中的资源,而无需再次向服务器请求。

HTTP 304响应码的作用是在资源未发生变化时,避免不必要的数据传输,节省网络带宽和加快页面加载速度。

2、 协商缓存怎么工作

协商缓存是指客户端和服务器之间通过一系列的通信来确定是否需要重新获取资源,还是可以使用本地缓存的一种缓存机制。它的工作过程如下:

  1. 客户端请求资源: 客户端发送一个HTTP请求给服务器,请求某个特定的资源。

  2. 服务器检查资源状态: 服务器收到请求后,会检查请求中携带的条件,如If-Modified-Since、If-None-Match等头部字段,以及请求中的其他信息,来确定客户端是否可以使用缓存的资源。

  3. 服务器返回响应: 如果服务器判断客户端的缓存是最新的,即资源没有发生变化,服务器会返回一个HTTP 304(Not Modified)响应码,告诉客户端可以使用本地缓存。如果资源发生了变化,则服务器会返回资源的内容和一个新的ETag或Last-Modified头部值。

  4. 客户端处理响应: 客户端收到服务器返回的响应后,根据响应的状态码来决定如何处理。如果是HTTP 304响应,客户端会从本地缓存加载资源;如果是资源已更新的情况,则客户端会使用服务器返回的新资源内容。

  5. 更新本地缓存: 如果服务器返回了新的资源内容,客户端会将这个新的资源内容存储到本地缓存中,并更新相应的缓存标识,如ETag或Last-Modified值。

通过协商缓存机制,客户端和服务器之间可以避免不必要的数据传输,提高网络传输效率,减少服务器负载,并加快页面加载速度。

3、 http2.0

HTTP/2.0是HTTP协议的一个更新版本,旨在提高网站性能和速度。它于2015年发布,是HTTP/1.x的继任者,引入了许多新特性和改进,其中包括:

  1. 二进制协议: HTTP/2使用二进制格式而不是文本格式来传输数据,这样可以更有效地压缩和解析数据,提高传输效率。

  2. 多路复用: HTTP/2允许在单个TCP连接上并行发送多个HTTP请求和响应,这消除了HTTP/1.x中的队头阻塞问题,提高了页面加载速度。

  3. 头部压缩: HTTP/2使用HPACK算法对请求和响应头部进行压缩,减少了头部传输的数据量,降低了延迟和带宽消耗。

  4. 服务器推送: HTTP/2支持服务器主动向客户端推送资源,减少了客户端请求的次数,提高了页面加载速度。

  5. 流控制: HTTP/2引入了流控制机制,允许客户端和服务器在发送数据时控制数据流量,避免了过载和性能下降。

  6. 优先级: HTTP/2允许客户端指定请求的优先级,服务器可以根据优先级来处理请求,提高关键资源的加载速度。

总的来说,HTTP/2通过引入新特性和改进现有功能,提高了网站的性能和速度,使得用户能够更快地加载页面和获取资源。

4、 CSRF攻击过程,怎么进行攻击

CSRF(Cross-Site Request Forgery)攻击是一种网络安全攻击,它利用了用户在登录状态下对网站的信任,通过在受害者的浏览器中执行未经授权的操作来实施攻击。以下是CSRF攻击的一般过程:

  1. 获取受害者凭证: 攻击者首先需要获取受害者的登录凭证,通常是通过诱导受害者访问恶意网站、点击恶意链接、或者在共享计算机上进行操作,使受害者的浏览器发送登录请求到目标网站。

  2. 构造恶意请求: 攻击者在恶意网站上构造一个包含目标网站的请求的HTML页面或表单,并将其隐藏在诱骗受害者点击的链接、图片、广告等元素中。

  3. 诱导受害者点击: 攻击者诱使受害者在已经登录目标网站的情况下,点击包含恶意请求的链接、图片等内容。受害者浏览器在执行这些请求时会自动携带目标网站的Cookie等认证信息。

  4. 执行恶意请求: 受害者点击了链接后,浏览器会自动发送包含目标网站认证信息的请求到目标网站,目标网站会认为这是受害者的合法请求并执行操作,比如转账、修改密码等。

  5. 攻击完成: 攻击者成功利用受害者的身份在目标网站上执行了恶意操作,从而完成了CSRF攻击。

为防止CSRF攻击,网站可以采取一些防御措施,如使用CSRF令牌(CSRF Token)、检查Referer头部、使用同源策略、限制敏感操作的访问权限等。

5、 快排算法

快速排序(Quicksort)是一种常见的排序算法,基于分治的思想。它的基本思想是选择一个基准元素(pivot),将数组分割成两个子数组,其中一个子数组的所有元素小于基准元素,另一个子数组的所有元素大于基准元素,然后递归地对这两个子数组进行排序。

以下是一个 JavaScript 实现的快速排序算法:

function quickSort(arr) {
    if (arr.length <= 1) {
        return arr;
    }

    // 选择基准元素
    const pivot = arr[Math.floor(arr.length / 2)];

    // 分割数组
    const left = [];
    const right = [];
    const equal = [];
    for (let i = 0; i < arr.length; i++) {
        if (arr[i] < pivot) {
            left.push(arr[i]);
        } else if (arr[i] > pivot) {
            right.push(arr[i]);
        } else {
            equal.push(arr[i]);
        }
    }

    // 递归地对子数组进行排序
    return quickSort(left).concat(equal, quickSort(right));
}

// 示例
const array = [5, 3, 8, 4, 2, 7, 1, 6];
console.log("Original array:", array);
const sortedArray = quickSort(array);
console.log("Sorted array:", sortedArray);

在上面的实现中,我们首先选择一个基准元素(这里选择数组中间的元素),然后将数组分割成三个子数组:left(小于基准元素)、equal(等于基准元素)、right(大于基准元素)。接下来,我们对 left 和 right 子数组进行递归调用快速排序,并将结果与 equal 子数组合并,最后返回排好序的数组。

快速排序的时间复杂度为 O(n log n),在大多数情况下具有很好的性能表现。然而,最坏情况下的时间复杂度为 O(n^2),当数组已经有序或者基准元素的选择不合适时可能发生。

6、 快排不稳定,怎么规避

快速排序(Quicksort)是一种不稳定的排序算法,这意味着相等元素的顺序在排序后可能会改变。要规避快速排序的不稳定性,可以采取以下方法:

  1. 使用稳定的排序算法: 如果对稳定性有要求,可以选择其他稳定的排序算法,如归并排序(Merge Sort)或计数排序(Counting Sort)等。

  2. 添加稳定性处理: 在快速排序的实现中,可以对相等元素进行额外处理,确保它们的顺序不会改变。比如在分区过程中,可以使用“小于等于”和“大于等于”来保持相等元素的相对顺序。

  3. 结合其他排序算法: 可以结合使用快速排序和其他排序算法,以利用快速排序的性能优势,同时确保排序的稳定性。例如,可以使用快速排序对大规模数据进行初步排序,然后使用稳定的排序算法对每个小分区进行排序。

  4. 优化实现: 在实现快速排序时,可以进行一些优化,以减少不稳定性的影响。例如,在选择主元素(pivot)时,选择中位数而不是固定位置的元素,以减少相等元素的分区变化。

  5. 使用库函数: 对于大多数编程语言,标准库中提供的排序函数通常是经过优化并且具有稳定性的,可以直接使用这些函数而不必担心不稳定性问题。

选择适当的方法取决于排序场景和对排序稳定性的要求。在大多数情况下,快速排序的性能优势可能更重要,而不稳定性可能是可以接受的。

7、 Hooks怎么工作

React Hooks是React 16.8及更高版本引入的一项重要功能,它们使函数组件能够拥有状态和其他React特性,而无需编写类组件。下面是React Hooks的工作原理:

  1. 无需类组件: 使用React Hooks,您可以在函数组件中使用状态(useState)、副作用(useEffect)、上下文(useContext)等React功能,而无需编写类组件。

  2. 函数调用顺序: 在函数组件中使用Hooks时,React依赖于Hooks的调用顺序来跟踪每个状态的对应关系。这意味着Hooks必须按照相同的顺序被调用,并且每次渲染时都需要以相同的顺序调用。

  3. Hook函数执行: 每当组件渲染时,React会执行函数组件,并依次调用其中的每个Hook函数。当React遇到useState、useEffect等Hooks时,它会在内部维护一个Hooks链表,并根据调用顺序查找和管理状态。

  4. Hooks状态管理: 对于useState Hook,React会为每个状态变量创建一个存储器,并将其保存在组件的内部状态中。对于useEffect Hook,React会根据依赖项列表来决定何时调用副作用函数,并在组件卸载时清理副作用。

  5. 生命周期钩子替代: Hooks不仅提供了状态和副作用管理的能力,还可以替代类组件中的生命周期方法。例如,useEffect Hook可以用来替代componentDidMount、componentDidUpdate和componentWillUnmount等生命周期方法。

  6. 可组合性: Hooks的另一个关键特性是它们的可组合性。您可以编写自定义Hooks来将常见逻辑封装在可重用的函数中,并在多个组件中共享。这样可以使代码更具可读性和可维护性。

总的来说,React Hooks通过在函数组件中使用特定的Hook函数,使得组件可以拥有状态和其他React特性,并通过Hooks之间的调用顺序来维护和管理组件状态和副作用。

8、 useCallback的缓存,第二次渲染时怎么拿到上一次的缓存对象

在 React 中,useCallback 是一个 Hook,用于创建一个 memoized 的回调函数。useCallback 的缓存机制确保了当依赖项不变时,返回的回调函数对象不会变化,从而减少不必要的函数重新创建,提高性能。

但是,useCallback 返回的是一个函数,而不是对象,所以不能直接拿到上一次的缓存对象。如果需要在第二次渲染时访问上一次的缓存对象,可以使用 useRef Hook 来保存它。

以下是一个示例:

import React, { useState, useCallback, useRef } from 'react';

function MyComponent() {
  const [count, setCount] = useState(0);
  const lastCallback = useRef(null);

  // 使用 useCallback 创建一个 memoized 的回调函数
  const memoizedCallback = useCallback(() => {
    console.log('Callback invoked');
    // 在回调函数中访问上一次的缓存对象
    console.log('Last callback:', lastCallback.current);
    // 更新 lastCallback 的值为当前回调函数
    lastCallback.current = memoizedCallback;
  }, [count]); // 依赖项为 count

  return (
    <div>
      <button onClick={() => setCount(count + 1)}>Increment Count</button>
      <br />
      <button onClick={memoizedCallback}>Invoke Callback</button>
    </div>
  );
}

export default MyComponent;

在上面的示例中,我们使用 useRef 创建了一个 lastCallback 的引用,并在每次组件渲染时保持不变。然后,我们在 useCallback 中访问这个引用,即可获取到上一次的缓存回调函数。需要注意的是,我们需要在回调函数内部手动更新 lastCallback 的值为当前的回调函数。

9、 项目最难的点

10、 项目有什么成就感的地方

11、 项目中的防抖的应用

反问:做游戏相关的,游戏内嵌的页面,游戏外:运营页面,pc运营后台;用react

&&应该是面完就挂了

作者:dioee
链接:www.nowcoder.com/discuss/484…
来源:牛客网