查看原文
其他

什么是单例模式?

编程导航和鱼友们 面试鸭 2024-01-21

大家好呀,今天是编程导航 30 天面试题挑战的第十八天,一起来看看今天有哪些优质面试题吧。

后端

题目一

什么是 MySQL 执行计划?如何获取执行计划并对其进行分析?

官方解析

MySQL 执行计划是指 MySQL 查询优化器生成的一份详细的查询执行计划,它展示了 MySQL 在执行查询时所采取的具体执行计划,包括表的访问顺序、数据读取方式、使用的索引、使用的排序方式等等。通过分析执行计划,可以帮助我们找出查询性能瓶颈所在,进而进行优化,提高查询效率。

要获取执行计划,可以在执行 SQL 语句时在前面添加 explain 关键字,例如:

explain select * from table where id = 1;

这样,MySQL 会输出该查询语句的执行计划。 执行计划中的各个字段含义如下:

  • id:每个 Select 子句或者是一个操作符或者是一个查询语句。
  • select_type:查询类型,表示查询的类型(简单查询、联合查询、子查询等等)。
  • table:查询涉及的表。
  • partitions:匹配的分区。
  • type:访问类型,表示 MySQL 在表中找到所需行的方式。
  • possible_keys:表示查询可能使用到的索引。
  • key:实际使用到的索引。
  • key_len:使用的索引长度。
  • ref:列与索引的比较。
  • rows:根据表统计信息及索引选用情况,大致估算出找到所需的记录所需要读取的行数。
  • filtered:返回结果的行数占总行数的比例。
  • Extra:包含 MySQL 解决查询的详细信息。

分析执行计划时,需要注意以下几个方面:

  • 扫描行数:rows 字段,表示查询所需扫描的行数,如果该值过大,说明查询效率不高,需要优化。
  • 使用索引:key 字段,表示查询所使用的索引,如果没有使用索引或者使用的不是最优索引,需要考虑优化。
  • 排序:Extra 字段,如果查询需要使用 filesort 排序,说明查询效率不高,需要优化。
  • 嵌套循环:如果查询类型是 nested loop,说明查询中包含嵌套循环,也需要考虑优化。

通过分析执行计划,可以确定查询优化的方向和方法,提高查询效率。

鱼皮补充:这里大家不用去记忆执行计划中各字段的含义,你可以给面试官举个例子,你是怎么使用查询计划来分析定位一次慢查询的。

鱼友的精彩回答

Gianhing 的回答

MySQL 执行计划是 MySQL 查询优化器分析 SQL 查询时生成的一份详细计划,包括表如何连接、是否走索引、表扫描行数等。通过这份执行计划,我们可以分析这条 SQL 查询中存在的问题(如是否出现全表扫描),从而进行针对优化。

MySQL 中可以在 SQL 语句的前面加上 explain 命令来获取执行计划,例如:

mysql> explain select * from t_user where id = 1;
+----+-------------+--------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
| id | select_type | table  | partitions | type  | possible_keys | key     | key_len | ref   | rows | filtered | Extra |
+----+-------------+--------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | t_user | NULL       | const | PRIMARY       | PRIMARY | 4       | const |    1 |   100.00 | NULL  |
+----+-------------+--------+------------+-------+---------------+---------+---------+-------+------+----------+-------+

其中,各字段的含义如下:

  • id:SELECT 查询的序列号,表示执行 select 子句的顺序(id 相同,执行顺序从上到下;id 不同,值越大越先执行;如果是并集结果,则 id 值为 NULL)
  • select_type:查询类型,来区分简单查询、联合查询、子查询等。常见的类型有:
    • SIMPLE:简单查询,不包含表连接或子查询
    • PRIMARY:主查询,外层的查询
    • SUBQUERY:子查询中第一个 SELECT
    • UNION:UNION 后面的 SELECT 查询语句
    • UNION RESULT:UNION 合并的结果
  • table:查询用到的表名
  • partitions:匹配的分区,没有分区的表为 NULL
  • type ★:连接的类型,常见的类型有(性能从好到差):
    • system:存储引擎能够直接知道表的行数(如 MyISAM)并且只有一行数据
    • const:通过索引一次找到,通常在用主键或唯一索引时出现
    • eq_ref:用主键或唯一索引字段作为连接表条件
    • ref:用普通索引的字段作为连接表条件
    • range:对索引列进行范围查询
    • index:利用索引扫描全表
    • all:全表扫描
  • possible_keys:可能用到的索引
  • key ★:实际使用的索引,没有使用为 NULL
  • key_len:索引字段的最大长度,在满足需求下越短越好
  • ref:当使用索引等值查询时,与索引作比较的列或常量
  • rows ★:预计扫描的行数,值越大,查询性能越差
  • filtered:表示返回结果的行数占需读取行数的百分比
  • Extra ★:有关查询执行的其他信息
    • using index:使用覆盖索引,不用回表查询
    • using where:使用 where 子句来过滤结果集
    • using temporary:使用到临时表来存储中间结果,可能会导致性能问题
    • using filesort:查询需要进行文件排序操作,可能会导致性能问题
    • using index condition:先根据能用索引的条件获取符合条件的数据行,然后在根据其他条件去过滤数据

带 ★ 是需要重点关注的字段

题目二

什么是云原生?它有哪些优缺点?

官方解析

云原生是一种开发和运行应用程序的方法,旨在利用云计算的弹性、可扩展性、可靠性和高可用性等优势。它通过将应用程序打包到容器中,使用容器编排工具进行管理,实现了应用程序在不同环境中的快速部署、弹性伸缩和高可用性

云原生的优点包括:

  1. 灵活性和可扩展性:容器可以快速部署和扩展,以满足不同的负载要求。
  2. 高可用性:容器编排工具可以自动检测和恢复容器故障,提供高可用性。
  3. 效率和成本优化:使用容器可以节省资源和成本,提高应用程序的运行效率。
  4. 安全性:容器隔离应用程序的运行环境,减少了安全漏洞的风险。

云原生的缺点包括:

  1. 学习曲线较陡峭:云原生技术较为复杂,需要学习一些新的技术和工具。
  2. 可能存在依赖问题:应用程序可能依赖于某些特定的云原生技术或工具,这可能导致一些限制或局限性。
  3. 管理和维护难度:容器编排工具可能需要额外的管理和维护,需要更多的操作和维护成本。

云原生的应用场景包括:

  1. 微服务架构:云原生技术非常适合构建微服务架构,将应用程序拆分为小型、自治的服务。
  2. 弹性伸缩:云原生技术可以根据应用程序的负载自动扩展或缩小容器的数量,以适应不同的负载要求。
  3. 快速部署:使用云原生技术,可以快速地部署和更新应用程序,提高开发和部署效率。
  4. 多云部署:云原生技术可以在多个云环境中运行,方便应用程序在不同云环境中的部署和迁移。
  5. 数据处理和分析:云原生技术可以处理大规模的数据处理和分析任务,提高数据处理效率。

鱼皮评论:这题可以在开头补充:什么是 “云”、什么是 “原生”,再去解释云原生的概念和好处

鱼友的精彩回答

HeiHei 的回答

云原生:

云原生是一种面向云计算架构的软件开发和部署方法论,旨在优化应用程序在云环境中的性能、弹性、可靠性和可扩展性。它强调使用容器、微服务、自动化管理和云原生编排工具来构建和管理应用程序,以适应云环境的动态性和复杂性。

云原生的优点:

  1. 高可扩展性:云原生技术可以帮助应用程序轻松扩展,使其能够在需要时快速适应业务增长或减少。
  2. 高可用性和弹性:云原生技术使用容器和微服务,可以使应用程序更加稳定和可靠。容器可以在单个节点或整个集群之间自由移动,从而在节点或集群发生故障时保持高可用性和弹性。
  3. 更快的部署:云原生技术可以通过自动化流程来加速软件部署,从而缩短开发到生产的时间。
  4. 更好的资源利用率:云原生技术可以帮助企业更好地利用其计算、存储和网络资源,从而提高效率并降低成本。

云原生的缺点:

  1. 技术门槛高:云原生技术需要一定的技术水平才能理解和应用,因此对于那些缺乏技术知识的企业而言可能较为困难。
  2. 管理复杂:使用云原生技术的应用程序可能需要更多的管理和监控,以确保其正常运行。这可能增加了管理的复杂性。
  3. 安全性挑战:容器和微服务可能增加了安全威胁,因此需要采取额外的安全措施来保护应用程序和数据。

题目三

什么是单例模式?使用单例模式有什么好处?有哪些常用的单例模式实现方式?各自的应用场景是什么?

官方解析

单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来访问该实例。单例模式的目的是确保类的一个唯一实例,因此其他类可以轻松地从一个可知的地方访问它。

单例模式有以下好处:

  • 节省系统资源:在系统中,如果有多个实例会造成资源浪费,而使用单例模式可以减少这种浪费。
  • 简化了对象访问:单例模式提供了一个全局的访问点,因此可以简化访问过程。

常用的单例模式实现方式有以下几种:

  • 饿汉式单例模式:在类加载时创建单例对象。缺点是不支持延迟加载
  • 懒汉式单例模式:在第一次使用时才创建单例对象。缺点是需要考虑线程安全问题。
  • 双重检查锁单例模式:在第一次使用时创建单例对象,并使用双重检查锁定来确保线程安全。枚举单例模式:在枚举类型中创建单例对象,可以防止反射和序列化攻击

应用场景:

  • 数据库连接池:通过单例模式,可以确保系统中只有一个数据库连接池。
  • 日志记录器:可以使用单例模式记录系统日志,这样可以确保系统中只有一个日志记录器。
  • 配置文件管理器:可以使用单例模式管理应用程序的配置文件,这样可以避免重复读取配置文件的开销。
  • 线程池:可以使用单例模式来确保系统中只有一个线程池。

一个例子是 Spring 框架中的 ApplicationContext,它是一个全局访问点,提供了一个管理 Bean 的中央注册表。由于 Spring 中的 Bean 只需创建一次,因此 ApplicationContext 使用单例模式确保只有一个实例。

鱼皮补充:有些面试官可能会让你手写一种单例模式的实现,建议大家在学习设计模式时,多写代码实践下

鱼友的精彩回答

爱吃鱼蛋的回答

介绍

单例模式是一种设计模式,它的目的是保证一个类只有一个实例,并提供一个全局的访问点。使用单例模式可以避免多次创建对象节省内存空间,同时也可以保证数据的一致性。在开发过程中使用单例模式有以下好处:

  1. 节省内存空间。单例模式只创建一个实例,避免了多次创建对象所造成的内存消耗。

  2. 简化代码。单例模式提供了一个全局的访问点,可以方便地调用实例的方法,避免了重复的代码。

  3. 保证数据的一致性。由于只有一个实例,可以避免并发访问时数据不一致的问题。

实现方式

实现单例模式的方式有很多,下面是一些常见实现单例模式的方式:

  • 饿汉式单例模式:在类加载时就创建了实例,因此保证了线程安全。但是可能会造成资源浪费,因为实例在使用前就已经创建了。
  • 懒汉式单例模式:实例的创建是在第一次使用时才进行的。这种方式需要注意线程安全,可以使用 synchronized 关键字或者双重检查锁定等方式来保证线程安全。
  • 静态内部类单例模式:这种方式可以保证线程安全,且实现简单。实例的创建是在第一次使用时才进行的。
  • 枚举单例模式:这种方式可以保证线程安全,且实现简单。枚举类型的属性在 Java 中只会被初始化一次,因此枚举单例模式可以保证只有一个实例
  • 双重检查锁定单例模式:这种方式可以保证线程安全,且实现相对简单。在第一次调用 getInstance()方法时进行了双重检查,保证了只有一个实例被创建。
  • 线程局部变量单例模式:这种方式可以保证线程安全,且实现简单。在单个线程内部只会创建一个实例,因此不会造成资源浪费。

这里提供一种使用了双重检查锁线程安全方式实现单例模式

public class Singleton {

    // 私有构造方法
    private Singleton() {}
    // 使用volatile禁止单例对象创建时的重排序
    private static volatile Singleton instance;

   // 对外提供静态方法获取该对象
    public static Singleton getInstance() {
  // 第一次判断,如果instance不为null,不进入抢锁阶段,直接返回实际
        if(instance == null) {
            synchronized (Singleton.class) {
                // 抢到锁之后再次判断是否为空
                if(instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}
区别

这些不同的实现方式各有优缺点,在项目开发过程中需要根据场景需求选择合适的实现方式

使用场景

单例模式在开发中有许多适用的场景,如:

  1. 数据库连接池:在多线程环境下,为了避免频繁地创建和释放数据库连接,可以使用单例模式来实现数据库连接池,保证系统中只有一个连接池实例
  2. 应用程序配置信息对象:在系统中需要读取应用程序配置信息时,为了避免重复读取和存储配置信息,可以使用单例模式来实现配置信息对象,保证系统中只有一个配置信息对象实例
  3. 线程池:在多线程环境下,为了避免频繁地创建和销毁线程,可以使用单例模式来实现线程池,保证系统中只有一个线程池实例

在我们日常开发中接触到的 Java 和 Spring 也有许多地方应用了单例模式:

  1. 在 Java 中,Runtime 类就是一个单例模式。这个类提供了访问 Java 虚拟机的运行时环境的方法,比如获取内存信息、获取 CPU 核心数等。由于每个 Java 应用程序只有一个 Java 虚拟机实例,因此Runtime类只需要一个实例即可,这就是单例模式的应用。

  2. 在 Spring 框架中,ApplicationContext 对象也是一个单例模式。ApplicationContext 对象是 Spring 框架中的容器对象,负责管理 Bean 对象的创建、初始化、依赖注入等操作。由于 ApplicationContext 对象的创建和初始化需要消耗大量的系统资源,因此在整个应用程序中只需要一个 ApplicationContext 对象实例即可,这就是单例模式的应用。

注意事项

单例模式虽然好,但是任何设计模式都会存在其弊端,因此在使用过程中需要注意以下问题:

  1. 线程安全问题。这个问题在饿汉式中是一个常见的问题,普通的饿汉式方案在多线程情况下容易出现并发问题导致创建多个不同的示例,因此在实现方案中可以使用加锁的方式保证线程的安全;

  2. 序列化和反序列化问题。在单例模式中存在着破坏单例的风险,而序列化反序列化便是其中之一。当我们使用序列化和反序列化创建单例对象时会发现创建出来的对象都是不一样的,违背了单例模式的初衷,因此在需要序列化和反序列化类中实现实现 Serializable 接口,并且提供一个 readResolve()方法,以保证反序列化后仍然是同一个实例;

  3. 反射问题。使用单例模式时,需要考虑防止反射攻击。因为破坏单例的另外一种方式便是反射,就算是前面提及到的序列化和反序列化问题,底层也是通过反射来破坏单例的。因此在开发过程中可以在构造方法中判断是否已经存在实例,如果存在则抛出异常,防止通过反射创建新的实例

航仔丶的回答

单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供全局访问点。使用单例模式可以减少系统性能开销,节约资源,对于一般频繁创建和销毁对象的可以使用单例模式。因为它限制了实例的个数,有利于垃圾回收。好的单例模式也能提高性能。单例模式常常用于任务管理器回收站网站的计数器等场景。

饿汉式

饿汉式是一种在类被加载时就创建对象的方法,因此不存在线程安全问题。但是,它可能导致类装载的原因有很多种,在单例模式中大多数都是调用 getInstance 方法,但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化 instance 显然没有达到 lazy loading 的效果。

public class Singleton {
    private static Singleton instance = new Singleton();
    private Singleton() {}
    public static Singleton getInstance() {
        return instance;
    }
}
2.懒汉式

懒汉式是一种在第一次使用时才创建对象的方法,因此可能存在线程安全问题。在多线程环境下,当多个线程同时调用 getInstance 方法时,可能会创建多个实例,因此需要使用同步锁 synchronized 防止多线程同时进入造成 instance 被多次实例化。但是,使用同步锁会降低程序的效率

public class Singleton {
    private static Singleton instance;
    private Singleton() {}
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}
3.双重检查锁实现懒汉式单例模式

在第一次调用时创建对象实例,如果对象已经创建则直接返回。双重检查锁实现懒汉式单例模式的写法如下:

public class SingletonDCL {
    private volatile static SingletonDCL instance;
    private SingletonDCL() {}
    public static SingletonDCL getInstance() {
        if (instance == null) {
            synchronized (SingletonDCL.class) {
                if (instance == null) {
                    instance = new SingletonDCL();
                }
            }
        }
        return instance;
    }
}
4.静态内部类实现单例模式

在第一次调用时创建对象实例,如果对象已经创建则直接返回。静态内部类实现单例模式的写法如下:

public class SingletonInnerClass {
    private SingletonInnerClass() {}
    public static SingletonInnerClass getInstance() {
        return LazyHolder.INSTANCE;
    }
    private static class LazyHolder {
        private static final SingletonInnerClass INSTANCE = new SingletonInnerClass();
    }
}
5.枚举类实现单例模式

在第一次调用时创建对象实例,如果对象已经创建则直接返回。枚举类实现单例模式的写法如下:

public enum SingletonEnum {
    INSTANCE;
    public void method() {
        System.out.println("枚举类中定义方法!");
    }
}

前端

题目一

Vue Router 的 router 对象有什么区别?

官方解析

在 Vue.js 中,router 都是 Vue Router 提供的对象,但它们的作用不同。

route 对象是一个只读对象,我们无法通过改变 $route 对象来改变当前路由。

router 对象可以通过编程的方式来改变当前路由,如通过 router.replace()、$router.go() 等方法。

总的来说,router 对象则是控制当前路由状态的方式。

鱼友的精彩回答

猫十二懿的回答

route 对象获取当前路由的各种信息,如 route.query 获取查询参数等。route 对象。

router.push、router.go 等。通过 $router 对象可以实现在代码中进行路由的跳转、修改 URL 等操作。

router 的主要区别在于:

router 是可读写的,用于编程式地操作路由。route 访问;而 router 访问。

会冒泡的可乐的回答

Vue Router 的 $route$router 对象都是路由相关的对象,它们之间的区别主要在于其作用范围和生命周期。

$route 对象是当前路由的详细信息,包括路由的 path、params、query、hash 等信息。当路由匹配成功后,$route 对象会被更新,并且可以通过 this.$route 属性获取到。$route 对象的作用范围是单次路由匹配,即当路由匹配成功后,$route 对象会被创建,并在路由匹配结束后被销毁。

$router 对象是 Vue Router 的实例,它代表了整个路由系统,包含了路由的跳转方法、路由导航守卫等路由相关的方法和属性。当路由创建时,$router 对象会被创建,并在路由创建和销毁的整个生命周期内存在。

题目二

介绍下从 HTTP/1.0、HTTP/1.1 到 HTTP/2 再到 HTTP/3 的演化过程,各个阶段相对前一阶段做了哪些优化?

官方解析

HTTP/1.0、HTTP/1.1 到 HTTP/2 再到 HTTP/3 的演化过程主要是为了解决 HTTP 协议在网络传输过程中出现的一些问题,提高网络传输效率和性能。

HTTP/1.0 是最早的 HTTP 协议,它使用一条长连接(keep-alive)传输一个请求和响应,存在以下问题:

  • 队头阻塞问题:因为只有一个连接,所以如果有一个请求被阻塞,后续请求也会被阻塞。
  • 无法多路复用:只能按顺序传输一个请求和响应,无法同时传输多个请求和响应。
  • 每次请求需要新建连接:每次请求都需要新建连接,连接的建立和关闭过程会消耗时间。

HTTP/1.1 引入了以下优化:

  • 持久连接:即连接重用,通过一个 TCP 连接传输多个请求和响应,减少了连接建立和关闭的时间。
  • 分块传输编码(chunked):把响应数据分成多个块,每个块前面加上长度信息,便于客户端逐步接收。
  • 虚拟主机(Virtual Host):通过在请求头中添加 Host 字段来区分不同的主机。

HTTP/2 引入了以下优化:

  • 多路复用:允许同时通过同一个连接并行传输多个请求和响应,解决了队头阻塞问题。
  • 二进制分帧:将传输的数据分成一个个二进制帧,每个帧都有自己的 ID,可以独立传输,解决了队头阻塞问题,提高了传输效率。
  • 头部压缩:使用 HPACK 算法对头部信息进行压缩,减少了头部信息的传输量。

HTTP/3 引入了以下优化:

  • QUIC 协议:使用 QUIC 协议替代 TCP,支持更快的连接建立和更快的重传,能够解决 TCP 队头阻塞TCP 握手延迟的问题。
  • 数据流分离:将一个连接分成多个数据流,每个数据流都有独立的 ID,可以独立控制和传输数据。

总的来说,HTTP/1.0、HTTP/1.1 到 HTTP/2 再到 HTTP/3 的演化过程主要是从连接的角度进行了优化,提高了并发能力和传输效率,提高了用户体验

鱼皮补充:这题还蛮重要的,建议大家学习一下,面试的时候很容易被问到:HTTP/2 为什么快之类的问题

鱼友的精彩回答

mos 的回答

HTTP/1.0 到 HTTP/1.1 的优化:

持久连接:在 HTTP/1.0 中,每次请求都需要建立一个新的TCP连接,而在 HTTP/1.1 中,引入了持久连接(也称为复用连接),这样可以在一个TCP连接上发送多个HTTP请求和响应,减少了TCP连接的建立和关闭所需的时间和资源消耗。 管线化:在 HTTP/1.1 中,支持请求管线化,即客户端可以同时发送多个请求,在服务端处理完第一个请求之前不必等待其它请求的返回。这种方式虽然提高了性能,但由于各个请求之间存在依赖关系,当其中一个请求出错时,会导致后续请求都失败。

HTTP/1.1 到 HTTP/2 的优化:

二进制传输:HTTP/1.x 使用明文文本进行通信,而 HTTP/2 引入了二进制格式来代替文本格式,这样可以减少解析数据的开销,提高通信效率。 多路复用:HTTP/1.x 中一个 TCP 连接只能同时处理一个请求,而 HTTP/2 中支持多路复用,即同一个连接可以同时传输多个请求和响应,这样可以避免浪费底层 TCP 连接和减少网络延迟。 数据流和帧:HTTP/2 中将请求和响应分割成若干个数据流,并对其进行编号,同时对每个数据流中的数据进行拆分成更小的帧进行传输,这样使得多个数据流可以并发交错地在一个连接上传输,从而提高了传输效率和速度。 首部压缩:HTTP/2 中采用 HPACK 算法对消息头进行压缩,避免了重复数据的传输,降低了传输量,提高了性能。

HTTP/2 到 HTTP/3 的优化:

对 QUIC 协议的使用:HTTP/3 将 HTTP 协议与 QUIC 协议结合起来,QUIC 是基于 UDP 的传输协议,相较于基于 TCP 的协议,QUIC 具有更低的延迟和更好的拥塞控制,从而提高了性能和稳定性。 报头压缩算法更新:HTTP/2 中采用的 HPACK 算法对消息头进行压缩,但该算法存在一些安全漏洞,因此 HTTP/3 中使用了 QPACK 算法对报头进行压缩,QPACK 算法具有更好的安全性和效率。 无阻塞式的流:HTTP/3 中使用了 QUIC 协议的无阻塞式流特性,使得数据能够更快地通过网络传输,提高了性能和稳定性。 总的来说,HTTP/1.0、HTTP/1.1 到 HTTP/2 再到 HTTP/3 的演化过程主要是从连接的角度进行了优化,提高了并发能力和传输效率,提高了用户体验。

解析上文中的复用连接和多路复用 :都是为了提高 HTTP 的性能,但它们的实现方式不同。

复用连接指的是在一个 TCP 连接上可以重复发送多个请求-响应对,从而避免了每次请求都要建立新的 TCP 连接的开销。这种方式可以减少TCP连接的建立和关闭所需的时间和资源消耗,但是由于 HTTP/1.x 中使用“队头阻塞”机制,即同一时刻只能处理一个请求,因此在传输多个请求时,需要按顺序一个一个发送,不能同时进行,会浪费带宽资源。

多路复用(Multiplexing)则是指在一个 TCP 连接上同时传输多个请求-响应对,这样多个请求可以并发交错地在一个连接上传输,从而减少了网络延迟,提高了传输效率和速度。HTTP/2 中就采用了多路复用技术来提高性能。在多路复用中,每个请求都有一个唯一的标识符,并且每个请求和响应都被分解成很小的数据包(称为帧),这些帧之间没有任何固定的顺序要求,所以可以随时根据需要交错发送。这种方式可以避免浪费底层 TCP 连接和减少网络延迟,更加高效。

总之,复用连接和多路复用都可以减少建立和关闭 TCP 连接的开销,从而提高 HTTP 的性能,但多路复用还能同时传输多个请求-响应对,更加高效。

题目三

什么是 CSS 工程化?你用过哪些相关的工具?

官方解析

CSS 工程化是指将 CSS 在项目中进行模块化、组件化、可维护性、可重用性等方面的处理,以达到工程化管理 CSS 的目的。

在 CSS 工程化中,通常会使用一些相关的工具来辅助管理 CSS,常用的工具包括:

  1. CSS 预处理器:如 Sass、Less、Stylus 等,可以通过变量、函数、混合等方式,提高 CSS 的可维护性和可重用性。
  2. CSS 后处理器:如 PostCSS,可以用来处理 CSS 代码,通过插件的形式可以实现一些自动化处理,如自动添加前缀、压缩 CSS 等。
  3. CSS 模块化工具:如 CSS Modules、styled-components 等,可以将 CSS 样式与组件代码结合在一起,提高 CSS 的可维护性和可重用性。
  4. CSS 命名规范:如 BEM、SMACSS、OOCSS 等,可以通过规范化 CSS 的命名方式,提高 CSS 的可读性和可维护性。

通过使用这些工具,可以提高 CSS 的可维护性、可重用性和可读性,从而使得前端开发更加高效、简洁。

鱼皮补充:建议大家实践一下上面提到的技术,最少掌握一个 CSS 预处理器。

星球活动

1.欢迎参与 30 天面试题挑战活动 ,搞定高频面试题,斩杀面试官!

2.欢迎已加入星球的同学 免费申请一年编程导航网站会员

3.欢迎学习 鱼皮最新原创项目教程,手把手教你做出项目、写出高分简历!

加入我们

欢迎加入鱼皮的编程导航知识星球,鱼皮会 1 对 1 回答您的问题、直播带你做出项目、为你定制学习计划和求职指导,还能获取海量编程学习资源,和上万名学编程的同学共享知识、交流进步。

💎 加入星球后,您可以:

1)添加鱼皮本人微信,向他 1 对 1 提问,帮您解决问题、告别迷茫!点击了解详情

2)获取海量编程知识和资源,包括:3000+ 鱼皮的编程答疑和求职指导、原创编程学习路线、几十万字的编程学习知识库、几十 T 编程学习资源、500+ 精华帖等!点击了解详情

3)找鱼皮咨询求职建议和优化简历,次数不限!点击了解详情

4)鱼皮直播从 0 到 1 带大家做出项目,已有 50+ 直播、完结 3 套项目、10+ 项目分享,帮您掌握独立开发项目的能力、丰富简历!点击了解详情

外面一套项目课就上千元了,而星球内所有项目都有指导答疑,轻松解决问题

星球提供的所有服务,都是为了帮您更好地学编程、找到理想的工作。诚挚地欢迎您的加入,这可能是最好的学习机会,也是最值得的一笔投资!

长按扫码领优惠券加入,也可以添加微信 yupi1085 咨询星球(备注“想加星球”):


继续滑动看下一个

什么是单例模式?

编程导航和鱼友们 面试鸭
向上滑动看下一个

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存