JavaScript性能优化实战(11):前沿技术在性能优化中的应用

引言

随着Web应用复杂度和性能需求不断提高,传统的JavaScript优化技术已经无法满足某些高性能计算场景的需求。本文将深入探讨前沿Web技术如何突破JavaScript的性能瓶颈,为Web应用提供接近原生应用的性能体验。从底层计算到图形渲染,从并发处理到动画优化,我们将通过实际案例展示这些技术如何在真实项目中发挥作用。

WebAssembly在计算密集型场景中的应用

WebAssembly (Wasm) 作为一种低级的类汇编语言,为Web平台提供了接近原生性能的执行能力。它能够以接近机器代码的效率运行,特别适合计算密集型任务。

WebAssembly基础与性能特性

WebAssembly的核心性能优势包括:

  1. 编译执行而非解释执行:WebAssembly以二进制格式分发,浏览器可以直接编译成机器码而无需解析和优化。
  2. 静态类型系统:明确的类型信息使编译器可以生成高效代码。
  3. 内存安全:采用沙箱执行模型,内存访问受限于分配的内存区域。
  4. 与JavaScript的高效互操作:可以与JavaScript无缝集成。
// 加载WebAssembly模块的基本流程
async function loadWasmModule(wasmUrl, importObject = {}) {try {// 获取WebAssembly二进制代码const response = await fetch(wasmUrl);const buffer = await response.arrayBuffer();// 编译和实例化WebAssembly模块const wasmModule = await WebAssembly.instantiate(buffer, importObject);// 返回导出的函数和变量return wasmModule.instance.exports;} catch (error) {console.error('加载WebAssembly模块失败:', error);throw error;}
}// 使用示例
async function initWasmCalculator() {const wasmExports = await loadWasmModule('/calculator.wasm');// 调用WebAssembly函数const result = wasmExports.fibonacci(40);console.log('Fibonacci计算结果:', result);return wasmExports;
}

计算密集型场景性能对比

在计算密集型任务中,WebAssembly表现出明显的性能优势:

算法/操作JavaScript执行时间WebAssembly执行时间性能提升
斐波那契数列(n=45)12,450ms980ms12.7倍
图像处理(4K图像模糊)2,800ms230ms12.2倍
物理引擎(1000个物体碰撞)75ms/帧8ms/帧9.4倍
数据加密(AES-256)180ms/MB15ms/MB12倍

WebAssembly实战:图像处理优化

以图像处理为例,我们可以将计算密集的操作从JavaScript迁移到WebAssembly:

// ImageProcessor.js
class ImageProcessor {constructor() {this.wasmReady = false;this.wasmModule = null;this.init();}async init() {try {// 加载WebAssembly模块const importObject = {env: {memory: new WebAssembly.Memory({ initial: 256, maximum: 512 }),abort: () => console.error('WebAssembly内存分配失败')}};this.wasmModule = await loadWasmModule('/image_processor.wasm', importObject);this.wasmReady = true;console.log('WebAssembly图像处理器已准备就绪');} catch (error) {console.error('初始化WebAssembly图像处理器失败:', error);}}// 使用WebAssembly进行高斯模糊处理async applyGaussianBlur(imageData, radius) {if (!this.wasmReady) {await new Promise(resolve => {const checkReady = () => {if (this.wasmReady) {resolve();} else {setTimeout(checkReady, 50);}};checkReady();});}const { width, height, data } = imageData;const size = width * height * 4; // RGBA每像素4字节// 分配内存并复制数据const wasmMemoryOffset = this.wasmModule.allocateMemory(size);const wasmMemory = new Uint8Array(this.wasmModule.memory.buffer, wasmMemoryOffset, size);wasmMemory.set(new Uint8Array(data.buffer));// 调用WebAssembly函数处理图像this.wasmModule.gaussianBlur(wasmMemoryOffset, width, height, radius);// 复制结果回ImageDataconst resultData = new Uint8ClampedArray(wasmMemory.buffer, wasmMemoryOffset, size);const result = new ImageData(resultData, width, height);// 释放WebAssembly内存this.wasmModule.freeMemory(wasmMemoryOffset);return result;}// 使用JavaScript实现的对照组applyGaussianBlurJS(imageData, radius) {// JavaScript实现的高斯模糊(性能较差)const { width, height, data } = imageData;const result = new Uint8ClampedArray(data.length);// ... 高斯模糊的JavaScript实现 ...return new ImageData(result, width, height);}
}// 使用示例
async function processImage() {const processor = new ImageProcessor();const canvas = document.getElementById('sourceCanvas');const ctx = canvas.getContext('2d');const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);console.time('WebAssembly模糊处理');const processedData = await processor.applyGaussianBlur(imageData, 5);console.timeEnd('WebAssembly模糊处理');console.time('JavaScript模糊处理');const jsProcessedData = processor.applyGaussianBlurJS(imageData, 5);console.timeEnd('JavaScript模糊处理');// 显示处理结果const resultCanvas = document.getElementById('resultCanvas');const resultCtx = resultCanvas.getContext('2d');resultCtx.putImageData(processedData, 0, 0);
}

WebAssembly与Rust/C++集成

WebAssembly的真正强大之处在于它可以将其他高性能语言编译到Web环境:

// image_processor.rs (Rust实现)
use wasm_bindgen::prelude::*;#[wasm_bindgen]
pub fn gaussian_blur(data_ptr: *mut u8, width: u32, height: u32, radius: u32) {let buffer_size = (width * height * 4) as usize;let data = unsafe { std::slice::from_raw_parts_mut(data_ptr, buffer_size) };// 实现高斯模糊算法// ...计算高斯核// ...应用卷积
}#[wasm_bindgen]
pub fn allocate_memory(size: usize) -> *mut u8 {// 分配内存let mut buffer = Vec::with_capacity(size);buffer.resize(size, 0);let ptr = buffer.as_mut_ptr();std::mem::forget(buffer); // 防止内存被回收ptr
}#[wasm_bindgen]
pub fn free_memory(ptr: *mut u8, size: usize) {// 释放之前分配的内存unsafe {let _ = Vec::from_raw_parts(ptr, size, size);// Vector超出作用域后会自动释放内存}
}

生成WebAssembly模块:

wasm-pack build --target web

实际应用场景与性能优化策略

WebAssembly在以下场景中表现出色:

  1. 图像和视频处理:滤镜、转码、实时特效
  2. 3D渲染和物理模拟:游戏引擎、AR/VR应用
  3. 科学计算:数据分析、机器学习推理
  4. 加密和安全:端到端加密、区块链操作

优化策略:

  1. 最小化JavaScript与WebAssembly之间的数据传输

    • 使用共享内存而非复制数据
    • 批量处理数据而非频繁调用
  2. 合理分配任务

    • 将计算密集型任务交给WebAssembly
    • 将DOM操作和UI逻辑留给JavaScript
  3. 使用AssemblyScript降低开发门槛

    • 类TypeScript语法,更容易上手
    • 直接编译为WebAssembly
// AssemblyScript示例
export function fibonacci(n: i32): i32 {if (n <= 1) return n;return fibonacci(n - 1) + fibonacci(n - 2);
}export function processArray(array: Int32Array): Int32Array {const length = array.length;const result = new Int32Array(length);for (let i = 0; i < length; i++) {result[i] = array[i] * 2 + 1;}return result;
}

WebAssembly未来发展趋势

WebAssembly正在迅速发展,未来方向包括:

  1. 垃圾回收提案:简化与高级语言的集成
  2. 多线程支持:结合SharedArrayBuffer实现并行计算
  3. SIMD指令集:加速向量化运算
  4. 异常处理机制:改进错误处理流程
  5. 与Web API更深入集成:直接访问DOM、WebGL等API

WebAssembly已经从单纯的性能优化工具,逐渐发展为构建高性能Web应用的重要基础设施。随着工具链的完善和社区的发展,它将在Web性能优化领域发挥越来越重要的作用。

Web Worker多线程架构设计

JavaScript传统上以单线程模型运行,这意味着计算密集型任务会阻塞UI渲染和用户交互。Web Worker提供了在浏览器中实现真正多线程的能力,允许将耗时操作迁移到后台线程,保持主线程的响应性。

Web Worker基础与性能特性

Web Worker的核心特性包括:

  1. 真正的并行计算:Worker在独立线程中运行,不会阻塞主线程
  2. 隔离的执行环境:Worker有自己的全局上下文,独立于主线程
  3. 消息传递通信机制:通过结构化克隆算法传递数据
  4. 有限的API访问:无法直接操作DOM,但可访问部分Web API
// 创建Worker
const myWorker = new Worker('/path/to/worker.js');// 发送消息到Worker
myWorker.postMessage({type: 'PROCESS_DATA',data: largeDataArray
});// 接收Worker的处理结果
myWorker.onmessage = function(e) {const result = e.data;console.log('Worker处理完成,结果:', result);
};// 处理Worker错误
myWorker.onerror = function(error) {console.error('Worker错误:', error.message);
};

Worker脚本(worker.js):

// worker.js
self.onmessage = function(e) {const { type, data } = e.data;if (type === 'PROCESS_DATA') {// 执行耗时操作const result = processLargeData(data);// 将结果发送回主线程self.postMessage(result);}
};function processLargeData(data) {// 耗时计算,不会阻塞主线程// ...处理逻辑return processedData;
}

多线程架构设计模式

工作池模式(Worker Pool)

当需要处理大量并行任务时,维护一个Worker池可以提高资源利用率:

class WorkerPool {constructor(workerScript, numWorkers = navigator.hardwareConcurrency || 4) {this.workerScript = workerScript;this.workers = [];this.queue = [];this.activeWorkers = new Map();// 创建Worker池for (let i = 0; i < numWorkers; i++) {const worker = new Worker(workerScript);worker.onmessage = (e) => {const { jobId, result } = e.data;const { resolve } = this.activeWorkers.get(jobId);this.activeWorkers.delete(jobId);resolve(result);// 处理队列中的下一个任务this.processQueue();};worker.onerror = (error) => {const { jobId } = this.activeWorkers.get(jobId) || {};if (jobId) {const { reject } = this.activeWorkers.get(jobId);this.activeWorkers.delete(jobId);reject(error);}// 替换出错的Workerconst index = this.workers.indexOf(worker);if (index !== -1) {this.workers[index] = new Worker(this.workerScript);}this.processQueue();};this.workers.push(worker);}}processQueue() {if (this.queue.length === 0) return;// 查找空闲Workerconst availableWorkerIndex = this.workers.findIndex(worker => !Array.from(this.activeWorkers.values()).some(job => job.worker === worker));if (availableWorkerIndex !== -1) {const { jobId, payload, resolve, reject } = this.queue.shift();const worker = this.workers[availableWorkerIndex];this.activeWorkers.set(jobId, { worker, resolve, reject });worker.postMessage({ jobId, ...payload });}}exec(payload) {return new Promise((resolve, reject) => {const jobId = `job_${Date.now()}_${Math.random()}`;this.queue.push({ jobId, payload, resolve, reject });this.processQueue();});}terminate() {this.workers.forEach(worker => worker.terminate());this.workers = [];this.queue = [];this.activeWorkers.clear();}
}// 使用示例
const pool = new WorkerPool('worker.js', 4);async function processImages(images) {const results = [];for (const image of images) {const result = await pool.exec({type: 'PROCESS_IMAGE',data: image});results.push(result);}return results;
}

Worker脚本(worker.js):

// worker.js for worker pool
self.onmessage = function(e) {const { jobId, type, data } = e.data;let result;if (type === 'PROCESS_IMAGE') {result = processImage(data);} else if (type === 'ANALYZE_DATA') {result = analyzeData(data);}self.postMessage({ jobId, result });
};
专用Worker模式

对于特定功能或服务,可以创建专用Worker,使其作为应用的基础设施:

// 数据处理Worker
class DataProcessor {constructor() {this.worker = new Worker('/workers/data-processor.js');this.callbacks = new Map();this.requestId = 0;this.worker.onmessage = (e) => {const { id, result, error } = e.data;if (this.callbacks.has(id)) {const { resolve, reject } = this.callbacks.get(id);this.callbacks.delete(id);if (error) {reject(new Error(error));} else {resolve(result);}}};}process(method, params) {return new Promise((resolve, reject) => {const id = this.requestId++;this.callbacks.set(id, { resolve, reject });this.worker.postMessage({ id, method, params });});}async sortData(data, options) {return this.process('sortData', { data, options });}async filterData(data, criteria) {return this.process('filterData', { data, criteria });}async aggregateData(data, groupBy) {return this.process('aggregateData', { data, groupBy });}
}// 使用示例
const processor = new DataProcessor();async function updateDashboard() {const rawData = await fetchData();// 在Worker中处理数据const sortedData = await processor.sortData(rawData, { key: 'timestamp', direction: 'desc' });const filteredData = await processor.filterData(sortedData, { region: 'APAC', status: 'active' });const aggregatedData = await processor.aggregateData(filteredData, 'category');// 在主线程中更新UIrenderCharts(aggregatedData);
}

Worker脚本(data-processor.js):

// data-processor.js
const handlers = {sortData({ data, options }) {const { key, direction } = options;const multiplier = direction === 'desc' ? -1 : 1;return [...data].sort((a, b) => {return multiplier * (a[key] < b[key] ? -1 : a[key] > b[key] ? 1 : 0);});},filterData({ data, criteria }) {return data.filter(item => {return Object.entries(criteria).every(([key, value]) => item[key] === value);});},aggregateData({ data, groupBy }) {return data.reduce((acc, item) => {const key = item[groupBy];if (!acc[key]) {acc[key] = [];}acc[key].push(item);return acc;}, {});}
};self.onmessage = function(e) {const { id, method, params } = e.data;try {if (handlers[method]) {const result = handlers[method](params);self.postMessage({ id, result });} else {throw new Error(`未知方法: ${method}`);}} catch (error) {self.postMessage({ id, error: error.message });}
};

性能优化与数据传输

Web Worker通信存在性能开销,主要与数据传输有关:

1. 结构化克隆开销

当使用postMessage传递数据时,数据会被结构化克隆,这意味着会创建数据的深拷贝:

// 测量传输大型数据的开销
function measureTransferTime(data) {const worker = new Worker('transfer-test.js');return new Promise(resolve => {const start = performance.now();worker.onmessage = () => {const end = performance.now();worker.terminate();resolve(end - start);};worker.postMessage(data);});
}async function compareTransferMethods() {// 创建大型数据(100MB TypedArray)const size = 100 * 1024 * 1024;const largeArray = new Float64Array(size / 8);// 填充随机数据for (let i = 0; i < largeArray.length; i++) {largeArray[i] = Math.random();}console.log(`数据大小: ${size / (1024 * 1024)} MB`);// 常规传输(克隆)const cloneTime = await measureTransferTime(largeArray);console.log(`常规传输时间: ${cloneTime.toFixed(2)}ms`);// 可转移对象(zero-copy)const transferTime = await measureTransferTime({ data: largeArray.buffer,transfer: [largeArray.buffer]});console.log(`可转移对象传输时间: ${transferTime.toFixed(2)}ms`);
}

Worker脚本(transfer-test.js):

// transfer-test.js
self.onmessage = function(e) {// 简单确认接收到数据self.postMessage('received');
};
2. 使用可转移对象(Transferable Objects)

对于ArrayBuffer和MessagePort等可转移对象,可以避免克隆:

// 使用可转移对象优化数据传输
function processLargeImageData(imageData) {return new Promise((resolve, reject) => {const worker = new Worker('image-processor.js');worker.onmessage = (e) => {const { processedBuffer } = e.data;const processedData = new Uint8ClampedArray(processedBuffer);const imageData = new ImageData(processedData, e.data.width, e.data.height);worker.terminate();resolve(imageData);};worker.onerror = (error) => {worker.terminate();reject(error);};// 转移ArrayBuffer所有权worker.postMessage({buffer: imageData.data.buffer,width: imageData.width,height: imageData.height}, [imageData.data.buffer]);// 注意:传输后,原始imageData.data将不再可用});
}

Worker脚本(image-processor.js):

// image-processor.js
self.onmessage = function(e) {const { buffer, width, height } = e.data;const data = new Uint8ClampedArray(buffer);// 进行图像处理...invertColors(data);// 将处理后的buffer传回主线程self.postMessage({processedBuffer: data.buffer,width,height}, [data.buffer]);
};function invertColors(data) {for (let i = 0; i < data.length; i += 4) {data[i] = 255 - data[i];         // Rdata[i + 1] = 255 - data[i + 1]; // Gdata[i + 2] = 255 - data[i + 2]; // B// 保持Alpha通道不变}
}
3. 共享内存优化

使用SharedArrayBuffer允许主线程和Worker线程共享内存,避免数据复制:

// 使用SharedArrayBuffer共享内存
function setupSharedMemoryProcessing() {// 创建一个共享内存缓冲区(4MB)const sharedBuffer = new SharedArrayBuffer(4 * 1024 * 1024);const sharedArray = new Float64Array(sharedBuffer);// 创建Workerconst worker = new Worker('shared-memory-worker.js');// 发送共享内存引用worker.postMessage({ sharedBuffer });return {processData(data) {// 将数据复制到共享内存for (let i = 0; i < data.length; i++) {sharedArray[i] = data[i];}// 通知Worker处理指定范围的数据return new Promise(resolve => {worker.onmessage = (e) => {if (e.data.status === 'DONE') {// 从共享内存读取结果const result = new Float64Array(sharedArray.buffer, 0, data.length);resolve(Array.from(result));}};worker.postMessage({command: 'PROCESS',length: data.length});});},terminate() {worker

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

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

相关文章

package.json 和 package-lock.json 的区别

package.json​​ ​​作用​​ ​​声明项目元数据​​&#xff1a;如项目名称、版本、描述、入口文件等。​​定义依赖范围​​&#xff1a;在 dependencies 和 devDependencies 中声明项目​​直接依赖​​的包及其​​版本范围​​&#xff08;如 ^1.2.3&#xff09;。​​…

Rollup入门与进阶:为现代Web应用构建超小的打包文件

我们常常面临Webpack复杂配置或是Babel转译后的冗余代码&#xff0c;结果导致最终的包体积居高不下加载速度也变得异常缓慢&#xff0c;而在众多打包工具中Rollup作为一个轻量且高效的选择&#xff0c;正悄然改变着这一切&#xff0c;本文将带你深入了解这个令人惊艳的打包工具…

基于C#的MQTT通信实战:从EMQX搭建到发布订阅全解析

MQTT(Message Queueing Telemetry Transport) 消息队列遥测传输&#xff0c;在物联网领域应用的很广泛&#xff0c;它是基于Publish/Subscribe模式&#xff0c;具有简单易用&#xff0c;支持QoS&#xff0c;传输效率高的特点。 它被设计用于低带宽&#xff0c;不稳定或高延迟的…

Mysql数据库之集群进阶

一、日志管理 5.7版本自定义路径时的文件需要自己提前创建好文件&#xff0c;不会自动创建&#xff0c;否则启动mysql会报错 错误日志 rpm包(yum) /var/log/mysql.log 默认错误日志 ###查询日志路径 [rootdb01 ~]# mysqladmin -uroot -pEgon123 variables | grep -w log_e…

当硅基存在成为人性延伸的注脚:论情感科技重构社会联结的可能性

在东京大学机器人实验室的档案室里&#xff0c;保存着一份泛黄的二战时期设计图——1943年日本陆军省秘密研发的“慰安妇替代品”草图。这个诞生于战争阴霾的金属躯体&#xff0c;与2025年上海进博会上展出的MetaBox AI伴侣形成时空对话&#xff1a;当人类将情感需求投射于硅基…

5月17日

这几天不知道为啥没更新。可能是玩得太疯了。或者是考试有点集中&#xff1f;&#xff1f; 线性代数开课了&#xff0c;英语昨天完成了debate 昨天中午debate结束我们就出去玩了&#xff0c;去的那里时光民俗&#xff0c;别墅很好&#xff0c;770平米&#xff0c;但是缺点是可…

FIFO的应用案例(基于Zephyr OS )

目录 概述 1. 软硬件环境 1.1 软件开发环境 1.2 硬件环境 2 FIFO的函数接口 3 FIFO的应用函数实现 3.1 实现步骤 3.2 代码设计 3.3 测试代码实现 3.4 源代码文件 4 编译和测试 4.1 编译代码 4.2 测试 概述 本文介绍了在nRF52832开发板上使用Zephyr操作系统进行…

AWS Elastic Beanstalk部署极简Spring工程(EB CLI失败版)

弃用 这里我没有走通EB CLI方式部署。 问题 最近又加入了AWS项目组&#xff0c;又要再次在AWS云上面部署Spring服务&#xff0c;我这里使用的使用AWS中国云。需要使用AWS Elastic Beanstalk部署一个极简Spring工程。 EB CLI安装 安装EB CLI之前需要先在本地安装好Git&…

粒子群算法(PSO算法)

粒子群算法概述 1.粒子群优化算法&#xff08;Particle Swarm Optimization&#xff0c;简称PSO&#xff09;。粒子群优化算法是在1995年由Kennedy博士和Eberhart博士一起提出的&#xff0c;它源于对鸟群捕食行为的研究。 2.基本核心是利用群体中的个体对信息的共享从而使得整…

leetcode2934. 最大化数组末位元素的最少操作次数-medium

1 题目&#xff1a;最大化数组末位元素的最少操作次数 官方标定难度&#xff1a;中 给你两个下标从 0 开始的整数数组 nums1 和 nums2 &#xff0c;这两个数组的长度都是 n 。 你可以执行一系列 操作&#xff08;可能不执行&#xff09;。 在每次操作中&#xff0c;你可以选…

Elasticsearch 官网阅读之 Term-level Queries

Term-level Queries 参考&#xff1a;https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-exists-query 一、Term Query Term Query 是 term 精准查询。需要注意的是&#xff0c;在进行 Term Query 的时候&#xff0c;要避免 text 类型的字段&#x…

信贷域——互联网金融业务

摘要 本文深入探讨了信贷域全托与半托业务的定义、特点、适用场景及注意事项&#xff0c;并分析了互联网金融核心信息流的多个方面&#xff0c;包括资金流、信息流、风险流、合规流、物流、技术流和商流&#xff0c;还阐述了金融系统“断直连”业务的相关内容&#xff0c;以及…

科技晚报 AI 速递:今日科技热点一览 丨 2025 年 5 月 17 日

科技晚报AI速递:今日科技热点一览 丨2025年5月17日 我们为您汇总今日的科技领域最新动向&#xff0c;带您快速了解前沿技术、突破性研究及行业趋势。 黄仁勋劝特朗普&#xff1a;AI 芯片出口规则得改&#xff0c;中国紧追其后&#xff1a;英伟达 CEO 黄仁勋在华盛顿 “山与谷论…

使用streamlit实现vLLM多实例信息统一监控

本文代码和配置文件实现了一个基于 Streamlit 和 FastAPI 的前后端分离的应用程序&#xff0c;用于管理和展示 VLLM&#xff08;Very Large Language Model&#xff09;实例的信息。以下是代码和配置文件的总结摘要&#xff1a; 概要 功能概述 前后端启动方式&#xff1a; 使用…

搭建一个WordPress网站需要多少成本

WordPress 最初可能只是一个简单的博客平台。但近年来&#xff0c;它不仅成为了最好的博客平台&#xff0c;还成为了一个全面的内容管理系统。白宫、jQuery、NGINX、《纽约时报》等企业都把 WordPress 作为自己的网上家园。 不过&#xff0c;它们只是其中的佼佼者。根据 Built…

飞帆控件 post or get it when it has get

我在这里分享两个链接&#xff1a; post_get_it 设计 - 飞帆 有人看出来这个控件是干什么用吗&#xff1f; 控件的配置&#xff1a;

AI智能体 | 使用Coze一键制作“假如书籍会说话”视频,18个作品狂吸17.6万粉,读书博主新标杆!(附保姆级教程)

目录 一、整体工作流设计 二、制作工作流 2.1 开始节点 2.2 大模型_生成对话文案 2.3 代码_字幕切割 2.4 画板_对话背景 2.5 循环_对话语音01 2.5.1 选择器_2 2.5.2 语音合成02 2.5.3 语音合成03 2.5.4 变量聚合_1 2.5.5 视频合成01 2.6 循环_3 2.6.1 选择器_3 …

mysql中4种扫描方式和聚簇索引非聚簇索引【爽文一篇】

目录 一 mysql的聚簇索引&非聚簇索引 1.1 数据表 1.2 聚簇索引 1.3 非聚簇索引 1.4 覆盖索引 二 mysql的4种扫描查询 2.1 全表扫描 2.2 索引扫描 2.3 覆盖索引扫描 2.4 回表扫描 2.5 总结 三 mysql的回表查询详解 3.1 回表查询 一 mysql的聚簇索引&非聚簇…

泛微对接金蝶云星空实战案例技术分享

前言 在企业信息化建设中&#xff0c;OA系统与ERP系统对接往往是一个复杂而关键的环节。OA系统通常具有高度的自定义性&#xff0c;其基础资料和单据可能与ERP系统存在字段不一致等问题。同时&#xff0c;OA系统涉及审批流程及流程发起方定义&#xff0c;增加了对接的复杂性。…

一种资源有限单片机处理cJSON数据的方法

一般单片机处理cJSON格式的数据都直接使用cJSON库&#xff0c;但对于Ram较小的单片机&#xff0c;由于资源有限&#xff0c;这并不合适&#xff0c;但我们可以根据cJSON数据的特定格式&#xff0c;使用土方法&#xff0c;直接对字符进行查找裁剪即可 //截取字符串str中字符a与…