JavaScript性能优化实战(13):性能测试与持续优化

news2025/5/24 15:35:47

在前面的系列文章中,我们探讨了各种JavaScript性能优化的方法和实战案例。然而,优化工作不应仅是一次性的努力,而应当成为开发流程中的常态。本篇将聚焦于如何建立系统化的性能测试体系,并实现持续的性能优化机制,确保应用长期保持出色的性能表现。

前端性能测试体系构建

随着前端应用日益复杂,系统性能对用户体验和业务成功的影响越来越大。然而,许多团队仍然采用临时性的、非系统化的方式进行性能测试和优化。建立一个完善的前端性能测试体系,对于持续交付高性能应用至关重要。

性能测试的核心维度

完整的前端性能测试体系应当覆盖以下几个核心维度:

  1. 加载性能:衡量应用从请求到可用所需的时间
  2. 运行时性能:评估应用在用户交互过程中的响应性和流畅度
  3. 内存使用:监控应用的内存占用情况和潜在的内存泄漏
  4. 网络效率:测量应用的网络请求数量、体积和时序
  5. 能耗性能:特别是在移动设备上,应用对电池寿命的影响

建立性能指标体系

性能测试的第一步是确定关键指标,这些指标应当既有技术维度的客观数据,也有用户体验的主观反映。

核心Web Vitals指标

Google的Core Web Vitals提供了衡量用户体验的标准化指标:

// 使用Web Vitals库收集核心指标
import {
   
  getCLS,
  getFID,
  getLCP,
  getFCP,
  getTTFB
} from 'web-vitals';

// 发送性能数据到分析服务
function sendToAnalytics({
    name, delta, value, id}) {
   
  const analyticsData = {
   
    metric: name,
    value: delta, // 增量值
    finalValue: value, // 最终值
    id: id, // 唯一标识符
    page: window.location.pathname,
    timestamp: Date.now()
  };
  
  // 发送到分析服务
  navigator.sendBeacon('/analytics', JSON.stringify(analyticsData));
}

// 监测并报告各项指标
getCLS(sendToAnalytics);  // 累积布局偏移
getFID(sendToAnalytics);  // 首次输入延迟
getLCP(sendToAnalytics);  // 最大内容绘制时间
getFCP(sendToAnalytics);  // 首次内容绘制时间
getTTFB(sendToAnalytics); // 首字节时间
自定义业务相关指标

除了标准化指标外,还应针对业务特点建立自定义指标,例如:

  • 关键业务流程性能:如电商网站的商品浏览到下单完成的全流程时间
  • 特定交互响应性:如复杂数据可视化应用中图表渲染和交互的响应时间
  • 长任务频率:应用中阻塞主线程超过50ms的任务数量和分布
// 自定义业务流程性能监测
class BusinessFlowPerformance {
   
  constructor(flowName) {
   
    this.flowName = flowName;
    this.steps = {
   };
    this.startTime = 0;
    this.endTime = 0;
  }

  startFlow() {
   
    this.startTime = performance.now();
    console.log(`Flow ${
     this.flowName} started`);
  }

  recordStep(stepName) {
   
    this.steps[stepName] = performance.now() - this.startTime;
    console.log(`Step ${
     stepName} completed at ${
     this.steps[stepName]}ms`);
  }

  endFlow() {
   
    this.endTime = performance.now();
    const totalDuration = this.endTime - this.startTime;
    console.log(`Flow ${
     this.flowName} completed in ${
     totalDuration}ms`);
    
    // 发送完整流程数据
    this.sendFlowData({
   
      flowName: this.flowName,
      totalDuration,
      steps: this.steps
    });
  }

  sendFlowData(data) {
   
    // 发送到数据分析服务
    fetch('/api/performance/business-flow', {
   
      method: 'POST',
      body: JSON.stringify(data),
      headers: {
    'Content-Type': 'application/json' }
    });
  }
}

// 使用示例
const checkoutFlow = new BusinessFlowPerformance('checkout');
checkoutFlow.startFlow();

// 在各关键步骤调用
// 用户点击结算按钮
checkoutFlow.recordStep('cart_to_checkout');

// 地址填写完成
checkoutFlow.recordStep('address_completed');

// 支付方式选择完成
checkoutFlow.recordStep('payment_selected');

// 订单确认
checkoutFlow.recordStep('order_confirmed');

// 流程完成
checkoutFlow.endFlow();

性能测试环境构建

有效的性能测试需要在标准化、可控的环境中进行,以确保结果的可重复性和可比性。

实验室测试环境设置

实验室测试环境应模拟真实的用户设备和网络条件:

// 使用Puppeteer进行性能测试的示例配置
const puppeteer = require('puppeteer');

async function runPerformanceTest(url, devicePreset, networkPreset) {
   
  // 启动浏览器
  const browser = await puppeteer.launch({
   
    headless: true,
    args: ['--no-sandbox', '--disable-setuid-sandbox']
  });
  
  // 创建新页面
  const page = await browser.newPage();
  
  // 设置设备模拟
  await page.emulate(puppeteer.devices[devicePreset]);
  
  // 模拟网络条件
  const client = await page.target().createCDPSession();
  await client.send('Network.enable');
  
  // 预设的网络配置
  const networkConfigs = {
   
    '3G': {
   
      'offline': false,
      'downloadThroughput': 750 * 1024 / 8,
      'uploadThroughput': 250 * 1024 / 8,
      'latency': 100
    },
    '4G': {
   
      'offline': false,
      'downloadThroughput': 4 * 1024 * 1024 / 8,
      'uploadThroughput': 2 * 1024 * 1024 / 8,
      'latency': 50
    }
  };
  
  await client.send('Network.emulateNetworkConditions', 
    networkConfigs[networkPreset] || networkConfigs['4G']
  );
  
  // 收集性能指标
  await page.evaluateOnNewDocument(() => {
   
    window.performanceMetrics = {
   
      FCP: 0,
      LCP: 0,
      CLS: 0,
      TTI: 0
    };
    
    // 首次内容绘制
    new PerformanceObserver((entryList) => {
   
      const entries = entryList.getEntries();
      const fcpEntry = entries[entries.length - 1];
      window.performanceMetrics.FCP = fcpEntry.startTime;
    }).observe({
    type: 'paint', buffered: true });
    
    // 最大内容绘制
    new PerformanceObserver((entryList) => {
   
      const entries = entryList.getEntries();
      const lcpEntry = entries[entries.length - 1];
      window.performanceMetrics.LCP = lcpEntry.startTime;
    }).observe({
    type: 'largest-contentful-paint', buffered: true });
    
    // 累积布局偏移
    new PerformanceObserver((entryList) => {
   
      let cumulativeScore = 0;
      for (const entry of entryList.getEntries()) {
   
        // 只计算没有用户输入的布局偏移
        if (!entry.hadRecentInput) {
   
          cumulativeScore += entry.value;
        }
      }
      window.performanceMetrics.CLS = cumulativeScore;
    }).observe({
    type: 'layout-shift', buffered: true });
  });
  
  // 访问目标页面并等待网络空闲
  const response = await page.goto(url, {
   
    waitUntil: 'networkidle2'
  });
  
  // 等待页面完全加载并可交互
  await page.waitForSelector('#main-content', {
    visible: true });
  
  // 提取性能指标
  const metrics = await page.evaluate(() => {
   
    // 等待TTI计算完成
    return new Promise(resolve => {
   
      // 模拟TTI计算
      setTimeout(() => {
   
        const navigationStart = performance.timing.navigationStart;
        const loadEventEnd = performance.timing.loadEventEnd;
        
        window.performanceMetrics.TTI = loadEventEnd - navigationStart;
        
        resolve(window.performanceMetrics);
      }, 1000);
    });
  });
  
  // 截图以备记录
  await page.screenshot({
    path: `${
     devicePreset}-${
     networkPreset}.png` });
  
  // 关闭浏览器
  await browser.close();
  
  return {
   
    url,
    devicePreset,
    networkPreset,
    metrics,
    statusCode: response.status()
  };
}

// 使用实例
async function runBatchTests() {
   
  const results = [];
  
  // 测试不同设备和网络组合
  const devices = ['iPhone X', 'Pixel 2', 'Desktop Chrome'];
  const networks = ['3G', '4G'];
  const urls = [
    'https://example.com',
    'https://example.com/products',
    'https://example.com/checkout'
  ];
  
  for (const url of urls) {
   
    for (const device of devices) {
   
      for (const network of networks) {
   
        const result = await runPerformanceTest(url, device, network);
        results.push(result);
      }
    }
  }
  
  // 生成性能测试报告
  generatePerformanceReport(results);
}

#### 真实用户监测(RUM)设置

实验室测试需要与真实用户数据相结合,才能全面反映应用性能:

```javascript
// 真实用户监测脚本示例
(function() {
   
  // 避免在非浏览器环境运行
  if (typeof window === 'undefined') return;
  
  // 确保Performance API可用
  if (!window.performance || 
      !window.performance.timing || 
      !window.performance.getEntriesByType) {
   
    console.warn('Performance API不完全支持,RUM数据可能不完整');
  }
  
  // 基础配置
  const config = {
   
    sampleRate: 0.1, // 采样率10%
    beaconEndpoint: '/analytics/rum',
    appVersion: '1.2.3',
    environment: 'production'
  };
  
  // 只对采样用户进行监测
  if (Math.random() > config.sampleRate) return;
  
  // 收集设备和浏览器信息
  const deviceInfo = {
   
    userAgent: navigator.userAgent,
    viewport: {
   
      width: window.innerWidth,
      height: window.innerHeight
    },
    devicePixelRatio: window.devicePixelRatio || 1,
    connection: navigator.connection ? {
   
      effectiveType: navigator.connection.effectiveType,
      downlink: navigator.connection.downlink,
      rtt: navigator.connection.rtt
    } : null
  };
  
  // 收集导航性能数据
  function collectNavigationTiming() {
   
    // 使用Performance Timeline API
    const navEntry = performance.getEntriesByType('navigation')[0];
    
    if (navEntry) {
   
      return {
   
        startTime: navEntry.startTime,
        domContentLoaded: navEntry.domContentLoadedEventEnd,
        loadTime: navEntry.loadEventEnd,
        domInteractive: navEntry.domInteractive,
        redirectCount: navEntry.redirectCount,
        redirectTime: navEntry.redirectEnd - navEntry.redirectStart,
        dnsTime: navEntry.domainLookupEnd - navEntry.domainLookupStart,
        tcpTime: navEntry.connectEnd - navEntry.connectStart,
        ttfb: navEntry.responseStart - navEntry.requestStart,
        responseTime: navEntry.responseEnd - navEntry.responseStart,
        domBuildingTime: navEntry.domComplete - navEntry.domInteractive,
      };
    }
    
    // 回退到旧API
    const timing = performance.timing;
    return {
   
      startTime: 0,
      domContentLoaded: timing.domContentLoadedEventEnd - timing.navigationStart,
      loadTime: timing.loadEventEnd - timing.navigationStart,
      domInteractive: timing.domInteractive - timing.navigationStart,
      redirectCount: 0,
      redirectTime: timing.redirectEnd - timing.redirectStart,
      dnsTime: timing.domainLookupEnd - timing.domainLookupStart,
      tcpTime: timing.connectEnd - timing.connectStart,
      ttfb: timing.responseStart - timing.requestStart,
      responseTime: timing.responseEnd - timing.responseStart,
      domBuildingTime: timing.domComplete - timing.domInteractive,
    };
  }
  
  // 收集并发送性能数据
  function sendPerformanceData() {
   
    const performanceData = {
   
      timestamp: Date.now(),
      page: window.location.pathname,
      referrer: document.referrer,
      deviceInfo,
      navigationTiming: collectNavigationTiming(),
      metrics: window.performanceMetrics || {
   },
      sessionId: getSessionId(),
      appVersion: config.appVersion,
      environment: config.environment
    };
    
    // 使用信标API发送数据
    if (navigator.sendBeacon) {
   
      navigator.sendBeacon(
        config.beaconEndpoint, 
        JSON.stringify(performanceData)
      );
    } else {
   
      // 回退到XHR
      const xhr = new XMLHttpRequest();
      xhr.open('POST', config.beaconEndpoint, true);
      xhr.setRequestHeader('Content-Type', 'application/json');
      xhr.send(JSON.stringify(performanceData));
    }
  }
  
  // 获取或创建会话ID
  function getSessionId() {
   
    let sessionId = sessionStorage.getItem('performance_session_id');
    if (!sessionId) {
   
      sessionId = generateUUID();
      sessionStorage.setItem('performance_session_id', sessionId);
    }
    return sessionId;
  }
  
  // 生成UUID
  function generateUUID() {
   
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
   
      const r = Math.random() * 16 | 0;
      const v = c === 'x' ? r : (r & 0x3 | 0x8);
      return v.toString(16);
    });
  }
  
  // 页面内容加载完毕后发送数据
  window.addEventListener('load', () => {
   
    // 延迟发送,等待其他指标收集完成
    setTimeout(sendPerformanceData, 1000);
  });
  
  // 页面卸载前尝试再次发送数据
  window.addEventListener('beforeunload', sendPerformanceData);
})();

性能测试工具集成

构建完整的前端性能测试体系需要集成多种专业工具,形成协同工作的工具链。

核心工具选择

不同的性能测试场景需要匹配相应的工具:

测试类型 推荐工具 主要场景
页面加载性能 Lighthouse, WebPageTest 整体页面加载分析和评分
运行时性能 Chrome DevTools, Puppeteer JavaScript执行和渲染性能分析
内存分析 Chrome Memory Panel, Heap Snapshot 内存泄漏和占用分析
真实用户监测 Google Analytics, New Relic, Sentry 生产环境中的性能数据收集
压力测试 k6, Artillery 高负载下的前端性能表现测试
工具链自动化集成

将这些工具整合到自动化测试流程中:

// 集成Lighthouse到CI/CD流程的示例脚本
const {
    exec } = require('child_process');
const lighthouse = require('lighthouse');
const chromeLauncher = require('chrome-launcher');
const fs = require('fs');
const path = require('path');

// 定义性能预算
const performanceBudgets = {
   
  'first-contentful-paint': 1800,  // ms
  'largest-contentful-paint': 2500, // ms
  'cumulative-layout-shift': 0.1,
  'total-blocking-time': 300,      // ms
  'speed-index': 3000,             // ms
  'interactive': 3500,             // ms
  'max-js-size': 350 * 1024,       // bytes
  'max-css-size': 70 * 1024,       // bytes
  'max-total-size': 1500 * 1024    // bytes
};

async function runLighthouseTest(url, options = {
    }) {
   
  // 启动Chrome
  const chrome = await chromeLauncher.launch({
   
    chromeFlags: ['--headless', '--disable-gpu', '--no-sandbox']
  });
  
  // 设置Lighthouse选项
  const opts = {
   
    port: chrome.port,
    output: 'json',
    logLevel: 'info',
    ...options
  };
  
  // 运行Lighthouse测试
  const results = await lighthouse(url, opts);
  
  // 关闭Chrome
  await chrome.kill();
  
  return results;
}

async function checkPerformanceBudgets(results, budgets) {
   
  const {
    audits } = results.lhr;
  const violations = [];
  
  // 检查FCP
  if (audits['first-contentful-paint'].numericValue > budgets['first-contentful-paint']) {
   
    violations.push({
   
      metric: 'First Contentful Paint',
      value: Math.round(audits['first-contentful-paint'].numericValue),
      budget: budgets['first-contentful-paint'],
      unit: 'ms'
    });
  }
  
  // 检查LCP
  if (audits['largest-contentful-paint'].numericValue > budgets['largest-contentful-paint']) {
   
    violations.push({
   
      metric: 'Largest Contentful Paint',
      value: Math.round(audits['largest-contentful-paint'].numericValue),
      budget: budgets['largest-contentful-paint'],
      unit: 'ms'
    });
  }
  
  // 检查CLS
  if (audits['cumulative-layout-shift'].numericValue > budgets['cumulative-layout-shift']) {
   
    violations.push({
   
      metric: 'Cumulative Layout Shift',
      value: audits['cumulative-layout-shift'].numericValue.toFixed(3),
      budget: budgets['cumulative-layout-shift'],
      unit: ''
    });
  }
  
  // 检查TBT
  if (audits['total-blocking-time'].numericValue > budgets['total-blocking-time']) {
   
    violations.push({
   
      metric: 'Total Blocking Time',
      value: Math.round(audits['total-blocking-time'].numericValue),
      budget: budgets['total-blocking-time'],
      unit: 'ms'
    });
  }
  
  // 检查Speed Index
  if (audits['speed-index'].numericValue > budgets['speed-index']) {
   
    violations.push({
   
      metric: 'Speed Index',
      value: Math.round(audits['speed-index'].numericValue),
      budget: budgets['speed-index'],
      unit: 'ms'
    });
  }
  
  // 检查TTI
  if (audits['interactive'].numericValue > budgets['interactive']) {
   
    violations.push({
   
      metric: 'Time to Interactive',
      value: Math.round(audits['interactive'].numericValue),
      budget: budgets['interactive'],
      unit: 'ms'
    });
  }
  
  // 检查JS大小
  const jsSize = audits['resource-summary'].details.items.find(item => item.resourceType === 'script').transferSize;
  if (jsSize > budgets['max-js-size']) {
   
    violations.push({
   
      metric: 'JavaScript Transfer Size',
      value: Math.round(jsSize / 1024) + ' KB',
      budget: Math.round(budgets['max-js-size'] / 1024) + ' KB',
      unit: ''
    });
  }
  
  // 检查CSS大小
  const cssSize = audits['resource-summary'].details.items.find(item => item.resourceType === 'stylesheet').transferSize;
  if (cssSize > budgets['max-css-size']) {
   
    violations.push({
   
      metric: 'CSS Transfer Size',
      value: Math.round(cssSize / 1024) + ' KB',
      budget: Math.round(budgets['max-css-size'] / 1024) + ' KB',
      unit: ''
    });
  }
  
  // 检查总资源大小
  const totalSize = audits['resource-summary'].details.items.find(item => item.resourceType === 'total').transferSize;
  if (totalSize > budgets['max-total-size']) {
   
    violations.push({
   
      metric: 'Total Transfer Size',
      value: Math.round(totalSize / 1024) + ' KB',
      budget: Math.round(budgets['max-total-size'] / 1024) + ' KB',
      unit: ''
    });
  }
  
  return violations;
}

// 主测试流程
async function runPerformanceTest() {
   
  try {
   
    console.log('启动性能测试...');
    
    // 测试环境URL
    const targetUrl = process.env.TEST_URL || 'https://staging.example.com';
    
    // 运行Lighthouse测试
    const results = await runLighthouseTest(targetUrl, {
   
      onlyCategories: ['performance']
    });
    
    // 保存测试报告
    const reportPath = path.join(__dirname, 'lighthouse-report.json');
    fs.writeFileSync(reportPath, JSON.stringify(results.lhr, null, 2));
    console.log(`测试报告已保存至: ${
     reportPath}`);
    
    // 验证性能预算
    const violations = await checkPerformanceBudgets(results, performanceBudgets);
    
    if (violations.length > 0) {
   
      console.error('性能预算违反警告:');
      violations.forEach(v => {
   
        console.error(`  - ${
     v.metric}: ${
     v.value}${
     v.unit} (预算: ${
     v.budget}${
     v.unit})`);
      })<

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

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

相关文章

树莓派内核源码的下载,配置,编译和替换

共享文件夹的创建 ubuntu创建共享文件夹可以实现和本地windows跨系统文件共享 下面是创建步骤 先在windows准备一个文件夹来当做共享文件夹 树莓派内核源码下载 1.在树莓派终端输入以下指令查看内核版本 uname -r我这里是已经编译替换过后的版本 2.选择树莓派对应的版本号下…

CentOS停止维护了,解决yum不能安装软件的问题

最近在使用CentOS的yum命令安装软件时&#xff0c;出现了如下错误&#xff1a; 原因&#xff1a; 这是因为CentOS在2024 年 6 月 30 日停止维护了&#xff0c;同时也移除了相关的软件镜像仓库&#xff0c;导致网站地址访问不了&#xff0c;从而下载不了软件。 解决方法&#xf…

过压保护电路设计和计算

设备供电电压因各种原因变得过高会烧坏设备,因此可以在前级加过压保护电路。 稳压二极管+PMOS 电路分析 1、当输入电压 Vin < 5.1V 时:(下图以输入电压 Vin = 5V 举例) D1是5.1V稳压管,此时输入电压Vin才5V,小于5.1V,所以稳压管D1未进入稳压状态,不导通。 5.1V稳…

20250523-BUG:无法加载“GameLib/Framework.h“头文件(已解决)

BUG&#xff1a;无法加载"GameLib/Framework.h"头文件&#xff08;已解决&#xff09; 最近在打开新的C项目时报了这个错&#xff0c;我是按照以下步骤来排除的BUG&#xff0c;希望对您有所帮助~ 检查【C/C】-【附加包含目录】中的路径有无问题&#xff0c;一般需要加…

OpenCv高阶(8.0)——答题卡识别自动判分

文章目录 前言一、代码分析及流程讲解&#xff08;一&#xff09;初始化模块正确答案映射字典&#xff08;题目序号: 正确选项索引&#xff09;图像显示工具函数 &#xff08;二&#xff09;轮廓处理工具模块&#xff08;三&#xff09;几何变换核心模块 二、主处理流程图像读取…

Python语法特点与编码规范

注释 单行注释 把#号当做注释符号 多行注释 python中并没有规定多行注释标记&#xff0c;通常使用单引号作为多行注释 中文注释 规定文件所用编码&#xff0c;当时是为解决python2不支持中文的问题 #codingutf-8代码缩进 python采用代码缩进和冒号区分代码层次&#xff0c…

反本能---如何对抗你的习以为常

目录 一、概述 二、自我提升 &#xff08;一&#xff09;我们为什么总想拖延 &#xff08;二&#xff09;如何有效应对拖延 &#xff08;三&#xff09;如何更好的自我控制 &#xff08;四&#xff09;为啥付出了没有回报 &#xff08;五&#xff09;如何提高学习效率 三…

(15)关于窗体的右键菜单的学习与使用,这关系到了信号与事件 event

&#xff08;1&#xff09;起因来源于 4.11 的老师讲的例题&#xff0c;标准的&#xff0c;规范的使用右键菜单的代码及参考资料如下&#xff1a; &#xff08;2&#xff09; 接着脱离上面的那个复杂的环境&#xff0c;用简单的例子测试一下 &#xff1a; 说明老师讲的都是对…

Ubuntu Desktop 24.04 常用软件安装步骤

文章目录 Ubuntu Desktop 24.04 常用软件安装步骤Snipaste F1快捷截图&#xff08;超方便 | 我6台电脑每台都用&#xff09;搜狗输入法快速浏览工具 | 空格键快速预览文件壁纸工具 | varietySSH 工具 | Termius 终端分屏工具 | TmuxCaffeine | 避免息屏小工具 一些设置将启动台…

Linux iSCSI存储共享实验指南

实验介绍 1、在Linux平台上通过iSCSI协议实现IP-SAN存储共享 2、掌握存储导出(export)和存储导入(import)的配置方法 3、学习iSCSI存储的发现、连接、断开和管理操作 1、实验环境 两台同网段的Linux虚拟机&#xff08;无需物理交换机&#xff09; 操作系统&#xff1a;Lin…

git入门之HEAD介绍

目录 前言一、HEAD 的含义与作用二、游离状态的触发场景及特征1. 触发条件2. 游离状态的特征 三、游离状态的常见使用情况1. 临时查看历史代码2. 保留游离状态的提交 四、注意事项与最佳实践1. 风险防范2. 状态检测技巧 总结 前言 本文介绍Git核心概念HEAD的定义&#xff0c;作…

车道线检测:自动驾驶的“眼睛”

在自动驾驶技术的庞大体系中&#xff0c;车道线检测扮演着至关重要的角色&#xff0c;它就像是自动驾驶汽车的“眼睛”&#xff0c;帮助车辆感知道路边界&#xff0c;从而实现安全、准确的行驶。今天&#xff0c;我们就来深入探讨一下车道线检测的奥秘&#xff0c;看看它是如何…

力扣面试150题--填充每个节点的下一个右侧节点指针 II

Day 45 题目描述 思路 初次做法&#xff1a;考虑到每一节点都要指向它右边的第一个节点&#xff0c;那么我们需要从根向下&#xff0c;最好每次提前处理根节点指向它右边的节点&#xff0c;那么符合这样的遍历方法&#xff0c;很容易i想到前序遍历&#xff0c;但是前序遍历是…

使用openvino和onnxruntime的SDK部署yolo11检测模型

这里的代码参考ultralytics代码库里面的examples文件夹下面的openvino和onnxruntime使用案例部署yolo11检测模型的代码。这两种部署框架和前面的tensorRT框架都是类似的&#xff0c;只是使用的接口不太一样。 PART A -- onnxruntime的使用 1.下载onnxruntime的推理框架 (1) …

C 语言学习笔记(指针4)

内容提要 指针 函数指针与指针函数二级指针 指针 函数指针与指针函数 函数指针 定义 函数指针本质上是指针&#xff0c;是一个指向函数的指针。函数都有一个入口地址&#xff0c;所谓指向函数的指针&#xff0c;就是指向函数的入口地址。&#xff08;这里的函数名就代表…

MySQL的相关操作

目录 一. 字符串函数 二. group by分组 2.1 作用 2.2 格式 2.3 举例 三. order by排序 3.1 格式 3.2 举例 四. limit 4.1 作用 4.2 举例 五. having 5.1 作用 5.2 举例 六. 正则表达式 七. 多表查询 7.1 定义 7.2 子查询 7.3 联合查询 纵向合并 7.4 交叉连…

鸿蒙HarmonyOS多设备流转:分布式的智能协同技术介绍

随着物联网和智能设备的普及&#xff0c;多设备间的无缝协作变得越来越重要。鸿蒙&#xff08;HarmonyOS&#xff09;作为华为推出的新一代操作系统&#xff0c;其分布式技术为实现多设备流转提供了强大的支持。本文将详细介绍鸿蒙多设备流转的技术原理、实现方式和应用场景。 …

XXE(外部实体注入)

目录 学习xxe前提&#xff1a;了解xml格式 1. XML基础 2. XXE基础知识 2.1. 结构 2.2. 定义与原理 2.3. XML实体类型 2.4. 攻击类型 2.5. 防御措施 3. pikachu靶场xxe练习 学习xxe前提&#xff1a;了解xml格式 1. XML基础 文档结构包括XML声明、DTD文档类型定义&…

jenkins凭据管理

用途: 存储构建需要与其他系统认证所使用的账户或者密码信息. Username with password类型存储Harbor或者其他系统的用户名和密码。GitLab API token类型存储Gitlab的用户API token。Secret text类型可以用来存储OpenShift等系统中的token。Certificate类型可以用户存储证书&am…

驱动开发硬核特训 · Day 31:理解 I2C 子系统的驱动模型与实例剖析

&#x1f4da; 训练目标&#xff1a; 从驱动模型出发&#xff0c;掌握 I2C 子系统的核心结构&#xff1b;分析控制器与从设备的注册流程&#xff1b;结合 AT24 EEPROM 驱动源码与设备树实例&#xff0c;理解 i2c_client 与 i2c_driver 的交互&#xff1b;配套高质量练习题巩固理…