大数据量列表渲染优化:前端实战经验让性能飙升50%,页面速度提升95%

news2024/11/24 8:55:17

引言:在处理大规模数据集渲染时,前端性能常常面临巨大的挑战。本文将探讨 react-virtualized-list 库如何通过虚拟化技术和 Intersection Observer,实现前端渲染性能飙升 50% 的突破,页面渲染速度提升 95% !🔥🚀

背景

最近,公司监控系统出现了加载卡顿和白屏问题,需要一个能够处理大规模数据渲染的方案。由于核心需求是列表项数据需要动态更新和自动刷新,所以用到了 react-virtualized-list 库。这个过程相当曲折,具体业务需求细节后面我会详细写一篇文章,这里先介绍一下react-virtualized-list库的特性、适用场景、API和实现原理。

希望对你有所帮助、有所借鉴。大家有什么疑问或者建议,欢迎在评论区一起讨论!

什么是虚拟化?

虚拟化技术,顾名思义,是一种通过仅渲染当前用户可见的数据项,而不是整个数据集,来优化性能的技术。这种技术在处理大量数据时尤为重要,因为它显著减少了 DOM 节点的数量,从而提高了性能。通过虚拟化,可以在用户滚动列表时动态加载和卸载元素,保持界面流畅。

下面是react-virtualized-list在虚拟化方面做的处理:

在这里插入图片描述

我们来看看真实的 DOM 情况!

在这里插入图片描述

react-virtualized-list 简介

react-virtualized-list 是一个专门用于显示大型数据集的高性能 React 组件库。它同时适用于 PC 端移动端,通过虚拟化技术实现了延迟加载和无限滚动功能,尤其是非常适合需要高效渲染和加载大量数据的应用场景,如聊天记录、商品列表等。

此外,react-virtualized-list 库还提供了场景适用的效果展示和示例代码。

核心特性 🔥🔥

  1. 高性能:仅渲染当前视口内的元素,显著减少 DOM 节点数量。
  2. 延迟加载:动态加载数据,避免一次性加载大量数据带来的性能问题。
  3. 无限滚动:支持无限滚动,用户可以持续滚动查看更多内容。
  4. 自定义渲染:提供灵活的 API,允许开发者自定义列表项的渲染方式。
  5. 视口内刷新:支持自动刷新视口内的内容,确保数据的实时性。
  6. 支持 TS 和 JS:适用于 TypeScript 和 JavaScript 项目。

安装

可以通过 npm 或 yarn 轻松安装 react-virtualized-list:

npm install react-virtualized-list
# 或者
yarn add react-virtualized-list

基本用法

下面是一个简单的示例,展示了如何使用 react-virtualized-list 创建一个无限滚动的虚拟化列表:

import React, { useState, useEffect } from 'react';
import VirtualizedList from 'react-virtualized-list';
import './style/common.css';

const InfiniteScrollList = () => {
  const [items, setItems] = useState([]);
  const [hasMore, setHasMore] = useState(true);

  const loadMoreItems = () => {
    // 模拟 API 调用,延迟 1 秒加载新数据
    setTimeout(() => {
      const newItems = Array.from({ length: 20 }, (_, index) => ({
        id: items.length + index,
        text: `Item ${items.length + index}`
      }));
      setItems(prevItems => [...prevItems, ...newItems]);
      setHasMore(newItems.length > 0);
    }, 1000);
  };

  useEffect(() => {
    loadMoreItems();
  }, []);

  const renderItem = (item) => <div>{item.text}</div>;

  return (
      <div className='content'>
        <VirtualizedList
          listData={items}
          renderItem={renderItem}
          containerHeight='450px'
          itemClassName='item-class'
          onLoadMore={loadMoreItems}
          hasMore={hasMore}
          loader={<div>Loading...</div>}
          endMessage={<div>No more items</div>}
        />
      </div>
  );
};

export default InfiniteScrollList;
/* ./style/common.css  */
.content {
    width: 350px;
    padding: 16px;
    border: 1px solid red;
    margin-top: 10vh;
}
.item-class {
    height: 50px;
    border: 1px solid blue;
    margin: 0px 0 10px;
    padding: 10px;
    background-color: #f0f0f0;
}

通过 onLoadMorehasMore 属性实现无限滚动,在用户滚动到列表底部时自动加载更多数据。这种功能常见于滚动加载下页数据。

在这里插入图片描述

进阶用法

动态加载数据

为了进一步提高性能,可以使用动态加载技术,只在需要时加载数据。以下是一个示例,展示了如何结合 react-virtualized-list 和动态数据加载:

import React, { useState, useEffect } from 'react';
import VirtualizedList from 'react-virtualized-list';
import './style/common.css';

const fetchProductData = async (product) => {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve({ description: `Description for ${product.name}`, imageUrl: `https://via.placeholder.com/150?text=Product+${product.id}` });
    }, 500);
  });
};

const fetchProducts = async (page) => {
  return new Promise((resolve) => {
    setTimeout(() => {
      const products = Array.from({ length: 10 }, (_, i) => ({
        id: page * 10 + i,
        name: `Product ${page * 10 + i}`
      }));
      resolve(products);
    }, 500);
  });
};

const DynamicInfiniteList = () => {
  const [products, setProducts] = useState([]);
  const [hasMore, setHasMore] = useState(true);
  const [page, setPage] = useState(0);

  const loadMoreProducts = async () => {
    const newProducts = await fetchProducts(page);
    setProducts(prevProducts => [...prevProducts, ...newProducts]);
    setPage(prevPage => prevPage + 1);
    if (newProducts.length < 10) setHasMore(false);
  };

  useEffect(() => {
    loadMoreProducts();
  }, []);
   
  return (
      <div className='content'>
        <VirtualizedList
          listData={products}
          renderItem={(product, data) => (
            <div>
              <h2>{product.name}</h2>
              <p>{data ? data.description : 'Loading...'}</p>
              {data && <img src={data.imageUrl} alt={product.name} />}
            </div>
          )}
          itemClassName='item-class-dynamic'
          fetchItemData={fetchProductData}
          onLoadMore={loadMoreProducts}
          hasMore={hasMore}
          containerHeight='500px'
          loader='Loading more products...'
          endMessage='No more products'
        />
      </div>
  );
};

export default DynamicInfiniteList;
/* ./style/common.css  */
.content {
    width: 350px;
    padding: 16px;
    border: 1px solid red;
    margin-top: 10vh;
}
.item-class-dynamic {
    height: 300px;
    padding: 20px;
    border-bottom: 1px solid #eee;
}

注意:在上面代码中,我们使用 onLoadMore 模拟商品列表的滚动加载,并在 VirtualizedList 组件的 fetchItemData 实现了商品详情的动态加载。这对于大数据集下,后端无法一次性返回数据非常有利

自定义渲染

react-virtualized-list 还提供了自定义渲染功能,开发者可以根据具体需求定制列表项的渲染方式。以下是一个示例,展示了如何自定义列表项的样式和内容:

import React from 'react';
import VirtualizedList from 'react-virtualized-list';

const data = Array.from({ length: 1000 }).map((_, index) => ({
  title: `Item ${index}`,
  index: index,
  description: `This is the description for item ${index}.`
}));

const ListItem = ({ item, style }) => (
  <div style={{ ...style, padding: '10px', borderBottom: '1px solid #ccc' }}>
    <h3>{item.title}</h3>
    <p>{item.description}</p>
  </div>
);

const itemStyle = {
    height: '100px',
    border: '1px solid blue',
    margin: '0px 0 10px',
    padding: '10px',
    backgroundColor: '#f0f0f0'
};

const MyVirtualizedList = () => (
  <div style={{width: '350px', padding: '16px', border: '1px solid red'}}>
    <VirtualizedList
        listData={data}
        itemStyle={itemStyle}
        renderItem={({ index, style }) => <ListItem item={data[index]} style={style} />}
        containerHeight='80vh'
    />
  </div>
);

export default MyVirtualizedList;

此外,react-virtualized-list 还提供了其他的用法场景和相关 API,详情请见使用文档。

在这里插入图片描述

实现原理(🔥核心重点,一定要了解)

在构建大型 Web 应用时,经常会遇到需要展示大量数据的情况,比如电子商务平台的产品列表等。传统的渲染方式可能会面临性能问题,因为它们需要在页面上同时呈现大量 DOM 元素,导致页面加载缓慢、滚动卡顿等问题。

为了解决这个问题,我们可以使用虚拟化列表来优化渲染过程。而 react-virtualized-list 库的核心在于通过虚拟化技术优化渲染过程。其主要原理包括以下几点:

在这里插入图片描述

1. 可视区域监测:利用Intersection Observer API

在虚拟化列表的实现中,一个关键步骤是监测可视区域内的元素。传统的方法是通过监听滚动事件并计算每个元素的位置来实现,然而这种方式效率较低。

// 获取需要监测可视性的元素
const elements = document.querySelectorAll('.target-element');

// 监听滚动事件
window.addEventListener('scroll', () => {
    // 计算每个元素的位置
    elements.forEach(element => {
        const rect = element.getBoundingClientRect();
        if (
            rect.top >= 0 &&
            rect.left >= 0 &&
            rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
            rect.right <= (window.innerWidth || document.documentElement.clientWidth)
        ) {
            // 元素在可视区域内
            // 执行相应操作
            console.log(`${element} is visible.`);
        }
    });
});

相比之下,我们可以利用现代浏览器提供的 Intersection Observer API 来更高效地监测元素的可见性变化。

// 定义一个 Intersection Observer
const observer = new IntersectionObserver(entries => {
    entries.forEach(entry => {
        // 如果元素可见
        if (entry.isIntersecting) {
            // 执行相应操作
            console.log(`${entry.target} is visible.`);
        }
    });
});

// 获取需要监测可视性的元素
const elements = document.querySelectorAll('.target-element');

// 监测每个元素
elements.forEach(element => {
    observer.observe(element);
});

这里我封装了一个 React Hooks useIntersectionObserver,提供了Intersection Observer API 的能力。

在这里插入图片描述

2. 仅渲染可见区域:优化性能

虚拟化列表的另一个关键优化是仅渲染可见区域内的元素,而不是渲染整个列表。这样做可以大大减少渲染所需的时间和资源,提高页面的性能表现。

import useIntersectionObserver from './useIntersectionObserver';

const [visibleItems, setVisibleItems] = useState<Set<number>>(new Set());

const handleVisibilityChange = useCallback((isVisible: boolean, entry: IntersectionObserverEntry) => {
    const index = parseInt(entry.target.getAttribute('data-index')!, 10);
    setVisibleItems(prev => {
      const newVisibleItems = new Set(prev);
      if (isVisible) {
        newVisibleItems.add(index);
      } else {
        newVisibleItems.delete(index);
      }
      return newVisibleItems;
    });
  }, []);
  
const { observe, unobserve } = useIntersectionObserver(containerRef.current, handleVisibilityChange, null, observerOptions);

3. 动态加载和卸载:保持内存使用最小化

最后,虚拟化列表还可以通过动态加载和卸载元素来保持内存使用最小化。当用户滚动到可视区域时,新的元素被动态加载,而离开可视区域的元素则被卸载,从而减少页面的内存占用。

在这里插入图片描述

const visibleRange = useMemo(() => {
    const sortedVisibleItems = [...visibleItems].sort((a, b) => a - b);
    const firstVisible = sortedVisibleItems[0] || 0;
    const lastVisible = sortedVisibleItems[sortedVisibleItems.length - 1] || 0;
    // 设置缓存区
    return [Math.max(0, firstVisible - BUFFER_SIZE), Math.min(listData.length - 1, lastVisible + BUFFER_SIZE)];
  }, [visibleItems, listData.length]);
  
const renderItems = () => {
    return listData.length ? listData.map((item, index) => {
      if (index >= visibleRange[0] && index <= visibleRange[1]) {
        return (
          <div
            className={itemClassName || undefined}
            style={itemContainerStyle}
            ref={node => handleRef(node, index)}
            key={index}
            data-index={index}
          >
            <VirtualizedListItem
              item={listData[index]}
              isVisible={visibleItems.has(index)}
              refreshOnVisible={refreshOnVisible}
              fetchItemData={fetchItemData}
              itemLoader={itemLoader}
            >
              {renderItem}
            </VirtualizedListItem>
          </div>
        );
      }
      return null;
    }) : (
      emptyListMessage ? emptyListMessage : null
    );
  };

当元素进入视口时,我们加载它;当元素离开视口时,我们卸载它。这样就可以保持页面上始终只有视口内的内容被渲染,从而提高页面的性能和响应速度。

除此之外,通过使用 useMemo 计算当前可见的列表项范围 (visibleRange),以及设置一个缓冲区 (BUFFER_SIZE);使用useMemouseCallback 用于性能优化的 Hook。它们帮助避免不必要的计算和重新渲染。

在这里插入图片描述

性能对比(🔥性能飙升 50%)

下面我们就来看下,传统滚动 Scroll 监听和 Intersection Observer API 的性能对比数据(假设在相同环境和数据集下测试):

方法初始渲染时间滚动性能内存使用
传统滚动监听300ms
Intersection Observer API150ms
  • 初始渲染时间:使用 Intersection Observer API 的初始渲染时间较短,因为只渲染可见区域。
  • 滚动性能:传统滚动监听由于频繁的滚动事件触发和位置计算,滚动性能较低;Intersection Observer API 的滚动性能较高,因为它利用了浏览器的优化机制。
  • 内存使用:Intersection Observer API 由于仅加载和渲染可见元素,内存使用更低。

性能测试代码分析

以下是一个示例,展示了如何使用 console.time 和 console.timeEnd 来测量性能:

// 测量传统滚动监听的性能
console.time('Scroll');
window.addEventListener('scroll', () => {
    // 模拟计算每个元素的位置
    const elements = document.querySelectorAll('.target-element');
    elements.forEach(element => {
        const rect = element.getBoundingClientRect();
        if (rect.top >= 0 && rect.bottom <= window.innerHeight) {
            // 模拟渲染逻辑
        }
    });
});
console.timeEnd('Scroll');

// 测量 Intersection Observer API 的性能
console.time('IntersectionObserver');
const observer = new IntersectionObserver(entries => {
    entries.forEach(entry => {
        if (entry.isIntersecting) {
            // 模拟渲染逻辑
        }
    });
});
const elements = document.querySelectorAll('.target-element');
elements.forEach(element => observer.observe(element));
console.timeEnd('IntersectionObserver');

注意:传统滚动监听方法还会涉及大量计算,这里仅简单测量了监听性能的统计部分。

传统的滚动监听方式通过监听 scroll 事件,在每次滚动时计算每个目标元素的位置,并判断其是否在视窗内。这部分代码的执行会阻塞主线程,尤其在滚动频繁的情况下可能导致性能问题,因为需要不断重新计算元素位置。

相比之下,Intersection Observer API 更高效。它可以检测元素是否可见,并在元素进入或退出视窗时触发回调函数,从而实现需要的功能。

在这里插入图片描述

性能总结

在性能方面,传统实现方法通常需要通过监听滚动(scroll)事件来计算元素位置。这种方法存在以下问题:

  • 性能消耗大:频繁监听滚动事件会导致性能消耗增加,尤其是在大型数据集的情况下。
  • 计算复杂度高:需要手动计算每个列表项与视口的交叉情况,逻辑复杂且容易出错。需要花费大量时间和精力来优化和调试这些计算逻辑。

相比之下,Intersection Observer API 的性能更优,具有以下优点:

  1. 性能开销低Intersection Observer API 利用浏览器的内部优化机制,减少了不必要的计算和事件触发,从而提高了性能。相比之下,传统的 scroll 事件监听方式由于密集触发,可能会导致较大的性能问题。
  2. 多元素监测Intersection Observer API 允许同时监测多个元素的交叉状态,而不需要为每个元素都绑定事件监听器。这使得在处理复杂布局和交互时更加高效。
  3. 异步执行:当元素进入或离开交叉状态时,Intersection Observer 会异步执行回调函数,不会阻塞主线程。这有助于保持页面的响应性和流畅性。
  4. 应用场景广泛Intersection Observer API 可以应用于多种场景,如懒加载、无限滚动、广告展示与统计、页面元素动画等。这些应用场景通常需要高效地处理元素与视口之间的交互。

综上所述,Intersection Observer API 在处理大型数据集和复杂交互时,相比传统的 scroll 事件监听方式,提供了更高的性能和更灵活的解决方案。

项目成果展示(🔥渲染速度提升95%)

下面我们看下优化后的性能,展示实际改进的用户体验和加载时间。

首先从视觉感官上看,几乎是一瞬间图表就加载了出来。我们接着再来看看接口Network与数据对比!

在这里插入图片描述

为了清楚地展示优化前后页面加载速度的提升,我们可以将相关数据整理成一个表格形式,如下所示:

优化指标优化前优化后加载速度提升
总耗时15000 毫秒(15秒)750 毫秒提速了95%

这个表格展示了优化措施的显著效果,从中可以看出,经过优化后,整体加载时间也从15000毫秒大幅减少至750毫秒,加载速度提高了95%。

总结

通过使用 react-virtualized-list 库,监控系统项目前端渲染性能得到了显著提升。统计结果显示:页面加载速度提高了 95%,用户体验得到了明显改善。如果你也在处理大数据集的渲染问题,不妨试试这个库。

希望本文能对你有所帮助,有所借鉴!大家有什么疑问或者建议,欢迎在评论区一起讨论。

参考资料

  1. Intersection Observer API
  2. react-virtualized-list
  3. 详解 Intersection Observer API ( 交叉观察器 )

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1830485.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

智能化软件开发微访谈·第三十一期 代码大模型训练、微调与增强

CodeWisdom “智能化软件开发沙龙是由CodeWisdom团队组织的围绕智能化软件开发、数据驱动的软件开发质量与效能分析、云原生与智能化运维等相关话题开展的线上沙龙&#xff0c;通过微信群访谈交流等线上交流方式将学术界与工业界专家学者汇聚起来&#xff0c;共同分享前沿研究进…

【Linux】使用 iptables 验证访问HDFS 所使用到的端口

目录 ​编辑 一、实操背景 二、iptables 简介 三、模拟操作 一、实操背景 背景&#xff1a; 在客户有外网的服务器需要访问内网大数据集群HDFS&#xff0c;使用iptable模拟测试需要开放的端口。 二、iptables 简介 具体介绍看文章&#xff1a; 【Linux】Iptables 详解与实战…

性能工具之 JMeter 常用组件介绍(七)

文章目录 一、后置处理器1、Regular Expression Extractor(正则表达式提取器)2、JSON Extractor(JSON表达式提取器)3、Regular Expression Extractor(正则表达式提取器) 二、小结 一、后置处理器 从上面可以看出后置处理可以插件挺多&#xff0c;在我工作生涯中常用的就是几个组…

【探索Linux命令行】从基础指令到高级管道操作的介绍与实践

目录 man 指令&#xff08;说明&#xff09; 介绍 cp 指令&#xff08;复制&#xff09; ​编辑 mv 指令&#xff08;移动&#xff09; ​编辑 cat 指令&#xff08;类似cout&#xff09; less&#xff08;查找&#xff09; head & tail&#xff08;打印&#xff…

基于jeecgboot-vue3的Flowable流程-流程表单显示控制

因为这个项目license问题无法开源&#xff0c;更多技术支持与服务请加入我的知识星球。 这个部分主要讲流程起始表单的显示控制&#xff0c;因为开始的时候可以进行输入处理&#xff0c;在流程过程中只能只读状态&#xff0c;当然返回到发起人节点也可以进行编辑提交 1、开始发…

Spring配置那些事

一、引言 配置是一个项目中不那么起眼&#xff0c;但却有非常重要的东西。在工程项目中&#xff0c;我们一般会将可修改、易变、不确定的值作为配置项&#xff0c;在配置文件/配置中心中设置。 比方说&#xff0c;不同环境有不同的数据库地址、不同的线程池大小等&#xff0c…

【NOI题解】1656. 是两位的偶数吗1658. 游乐设施1659. 是否含有数字5 1660. 今天要上课吗1661. 宇航员选拔

文章目录 一、前言二、问题问题&#xff1a;1656. 是两位的偶数吗问题&#xff1a;1658. 游乐设施问题&#xff1a;1659. 是否含有数字5问题&#xff1a;1660. 今天要上课吗问题&#xff1a;1661. 宇航员选拔 三、感谢 一、前言 本章节主要对关于分支结构的中需要进行逻辑运算…

OpenCV目标识别

一 图像轮廓 具有相同颜色或强度的连续点的曲线。 图像轮廓的作用 可以用于图像分析 物体的识别与检测 注意 为了检测的准确性&#xff0c;需要先对图像进行二值化或Canny操作。 画轮廓时会修改输入的图像。 轮廓查找的API findContours(img,mode,ApproximationMode,...)…

GUI Guider(V1.7.2) 设计UI在嵌入式系统上的应用(N32G45XVL-STB)

目录 概述 1 使用GUI Guider 设计UI 1.1 创建页面 1.2 页面切换事件实现 1.3 生成代码和仿真 1.3.1 生成和编译代码 1.3.2 仿真UI 2 GUI Guider生成的代码结构 2.1 代码结构介绍 2.2 Project目录下的文件 3 板卡上移植UI 3.1 加载代码至工程目录 3.2 主函数中调…

新旧torch中傅里叶变换实现(fft)

由泰勒级数我们知道&#xff0c;一个函数可以被分解成无穷个幂函数叠加的形式&#xff0c;于是同样地&#xff0c;一个周期函数也可以被分解成多个周期函数叠加&#xff0c;于是自然而然地&#xff0c;三角函数符合这个需求&#xff0c;由傅里叶级数我们可以将周期函数分解成无…

【车载音视频AI电脑】铁路视频监控系统解决方案

方案简介 铁路视频监控系统解决方案针对铁路行业安全运营保障需求&#xff0c;根据中国铁路总公司的技术规范要求&#xff0c;基于铁路系统的IP网络&#xff0c;采用先进的视频监控技术&#xff0c;构建一套完备的数字化、智能化、分布式铁路综合视频监控系统&#xff0c;实现视…

第二证券A股重要变化!今起实施

A股系列重要指数迎来样本股调整&#xff01; 此前&#xff0c;深交所及其全资子公司深证信息发布公告&#xff0c;将对深证成指、创业板指、深证100&#xff08;以下统称“深市中心指数”&#xff09;施行样本股定时调整。此次调整于6月17日&#xff08;今日&#xff09;正式施…

关于电脑文件的规划思考

概述 设置C、D、E、F 四个盘 C盘&#xff1a;系统数据使用&#xff0c;操作系统、其他软件需要用到的系统性资源 D盘&#xff1a;应用软件区 的使用&#xff0c;数据库、navacat、idea、visual studio、浏览器、向日葵、虚拟机…… E盘&#xff1a;工作区&#xff1a;公司资料…

如何移植libwebsockets

libwebsockets是一个高性能的开源C语言库&#xff0c;专为实现WebSocket协议及相关的HTTP协议而设计。它不仅使开发者能够在客户端与服务器端轻松构建WebSocket连接&#xff0c;还可以用作标准HTTP服务器。WebSocket是一种在单个TCP连接上进行全双工通信的协议&#xff0c;可以…

APS为什么是业务、开发、数据和算法的结合体

获取更多资讯,赶快关注上面的公众号吧! 文章目录 一 引言二 业务是灵魂2.1 生产类型2.2 生产模式2.3 生产约束三 开发是支撑3.1 开发语言3.2 技术架构3.3 内存计算3.4 系统集成3.5 系统交互四 数据是基础五 算法是核心5.1 问题建模5.2 算法建模总结APS系统的实施是一个类似阶…

技术心得总结:a 标签实现新标签页打开功能

最近&#xff0c;有用户提出希望在点击菜单项时&#xff0c;能够在新标签页中打开对应的链接功能。这类似于我们常用的右键菜单中的“在新标签页打开链接”功能。经过对需求的分析和代码的查看&#xff0c;我们找到了实现这一功能的方法。 原始实现 最初的跳转实现是通过用户触…

three.js 基础01

1.场景创建 Scene() 2.常用形状集几何体「Geometry」[可设置长宽高等内容&#xff0c;如&#xff1a;new THREE.BoxGeometry(...)] 长方体 BoxGeometry圆柱体 CylinderGeometry 球体SphereGeometry圆锥体ConeGeometry矩形平面 PlaneGeometry 圆面体 CircleGeo…

Linux中文件查找相关命令比较

Linux中与文件定位的命令有find、locate、whereis、which&#xff0c;type。 一、find find命令最强&#xff0c;能搜索各种场景下的文件&#xff0c;需要配合相关参数&#xff0c;搜索速度慢。在文件系统中递归查找文件。 find /path/to/search -name "filename"…

人工智能发展历程了解和Tensorflow基础开发环境构建

目录 人工智能的三次浪潮 开发环境介绍 Anaconda Anaconda的下载和安装 下载说明 安装指导 模块介绍 使用Anaconda Navigator Home界面介绍 Environment界面介绍 使用Jupter Notebook 打开Jupter Notebook 配置默认目录 新建文件 两种输入模式 Conda 虚拟环境 添…

《软件测试52讲》——测试基础知识篇

1 你真的懂测试吗&#xff1f;从“用户登录”测试谈起 从“用户登录”测试谈起&#xff0c;“用户登录”功能作为测试对象 作为测试工程师&#xff0c;你的目标是要保证系统在各种应用场景下的功能是符合设计要求的&#xff0c;所以你需要考虑的测试用例就需要更多、更全面。 …