Webpack: 基于Sourcemap源码映射原理与使用技巧

news2024/12/23 15:48:22

概述

Sourcemap 协议 最初由 Google 设计并率先在 Closure Inspector 实现,它的主要作用就是将经过压缩、混淆、合并的产物代码还原回未打包的原始形态,帮助开发者在生产环境中精确定位问题发生的行列位置,例如:
在这里插入图片描述

在 Webpack 内部,这段生成 Sourcemap 映射数据的逻辑并不复杂,一句话总结:在 processAssets 钩子遍历产物文件 assets 数组,调用 webpack-sources 提供的 map 方法,最终计算出 asset 与源码 originSource 之间的映射关系。

这个过程真正的难点在于 「如何计算映射关系」,因此本文会展开详细讲解 Sourcemap 映射结构与 VLQ 编码规则,以及 Webpack 提供的 devtool 配置项的详细用法。

Sourcemap 映射结构

Sourcemap 最初版本生成的 .map 文件非常大,体积大概为编译产物的 10 倍;V2 之后引入 Base64 编码等算法,将之减少 20% ~ 30%;而最新版本 V3 又在 V2 基础上引入 VLQ 算法,体积进一步压缩了 50%。

这一系列进化造就了一个效率极高的 Sourcemap 体系,但伴随而来的则是较为复杂的 mappings 编码规则。V3 版本 Sourcemap 文件由三部分组成:

  • 开发者编写的原始代码;
  • 经过 Webpack 压缩、转化、合并后的产物,且产物中必须包含指向 Sourcemap 文件地址的 //# sourceMappingURL=https://xxxx/bundle.js.map 指令;
  • 记录原始代码与经过工程化处理代码之间位置映射关系 Map 文件。

页面初始运行时只会加载编译构建产物,直到特定事件发生 —— 例如在 Chrome 打开 Devtool 面板时,才会根据 //# sourceMappingURL 内容自动加载 Map 文件,并按 Sourcemap 协议约定的映射规则将代码重构还原回原始形态,这既能保证终端用户的性能体验,又能帮助开发者快速还原现场,提升线上问题的定位与调试效率。

例如,在 Webpack 中设置 devtool = 'source-map' 即可同时打包出代码产物 xxx.js 文件与同名 xxx.js.map 文件,Map 文件通常为 JSON 格式,内容如:

{
    "version": 3,
    "sources": [
        "webpack:///./src/index.js"
    ],
    "names": ["name", "console", "log"],
    "mappings": ";;;;;AAAA,IAAMA,IAAI,GAAG,QAAb;AAEAC,OAAO,CAACC,GAAR,CAAYF,IAAZ,E",
    "file": "main.js",
    "sourcesContent": [
        "const name = 'tecvan';\n\nconsole.log(name)"
    ],
    "sourceRoot": ""
}

各字段含义分别为:

  • version: 指代 Sourcemap 版本,目前最新版本为 3
  • names:字符串数组,记录原始代码中出现的变量名;
  • file:字符串,该 Sourcemap 文件对应的编译产物文件名;
  • sourcesContent:字符串数组,原始代码的内容;
  • sourceRoot:字符串,源文件根目录;
  • sources:字符串数组,原始文件路径名,与 sourcesContent 内容一一对应;
  • mappings:字符串数组,记录打包产物与原始代码的位置映射关系。

使用时,浏览器会按照 mappings 记录的数值关系,将产物代码映射回 sourcesContent 数组所记录的原始代码文件、行、列位置,这里面最复杂难懂的点就在于 mappings 字段的规则。

举个例子,对于下面的代码:

编译前编译后
const name = 'tecvan'; console.log(name) /******/ (() => { // webpackBootstrap var __webpack_exports__ = {}; /*!**********************!*\ !*** ./src/index.js ***! \**********************/ var name = 'tecvan'; console.log(name); /******/ })() ; //# sourceMappingURL=main.js.map

devtool = 'source-map' 时,Webpack 生成的 mappings 字段为:

;;;;;AAAA,IAAMA,IAAI,GAAG,QAAb;AAEAC,OAAO,CAACC,GAAR,CAAYF,IAAZ,E

字段内容包含三层结构:

  • ; 分割的行映射,每一个 ; 对应编译产物每一行到源码的映射,上例经过分割后:
[
  // 产物第 1-5 行内容为 Webpack 生成的 runtime,不需要记录映射关系
  '', '', '', '', '', 
  // 产物第 6 行的映射信息
  'AAAA,IAAMA,IAAI,GAAG,QAAb', 
  // 产物第 7 行的映射信息
  'AAEAC,OAAO,CAACC,GAAR,CAAYF,IAAZ,E'
]
  • , 分割的片段映射,每一个 , 对应该行中每一个代码片段到源码的映射,上例经过分割后:
[
  // 产物第 1-5 行内容为 Webpack 生成的 runtime,不需要记录映射关系
  '', '', '', '', '', 
  // 产物第 6 行的映射信息
  [
    // 片段 `var` 到 `const` 的映射
    'AAAA', 
    // 片段 `name` 到 `name` 的映射
    'IAAMA', 
    // 等等
    'IAAI', 'GAAG', 'QAAb'], 
  // 产物第 7 行的映射信息
  ['AAEAC', 'OAAO', 'CAACC', 'GAAR', 'CAAYF', 'IAAZ', 'E']
]
  • 第三层逻辑为片段映射到源码的具体位置,以上例 IAAMA 为例:
    • 第一位 I 代表该代码片段在产物中列数;
    • 第二位 A 代表源码文件的索引,即该片段对标到 sources 数组的元素下标;
    • 第三位 A 代表片段在源码文件的行数;
    • 第四位 M 代表片段在源码文件的列数;
    • 第五位 A 代表该片段对应的名称索引,即该片段对标到 names 数组的元素下标。

上述第1、2层逻辑比较简单,唯一需要注意的是片段之间是一种相对偏移关系,例如对于上例第六行映射值:AAAA,IAAMA,IAAI,GAAG,QAAb,每一个片段的第一位 —— 即片段列数为 A,I,I,G,Q,分别代表:

  • A :第 A 列;
  • I :第 A + I 列;
  • I :第 A + I + I 列;
  • G :第 A + I + I + G 列;
  • Q :第 A + I + I + G + Q 列。

这种相对偏移能减少 Sourcemap 产物的体积,提升整体性能。注意,第三层逻辑中的片段位置映射则用到了一种比较高效数值编码算法 —— VLQ(Variable-length Quantity)。

VLQ 编码

VLQ 是一种将整数数值转换为 Base64 的编码算法,它先将任意大的整数转换为一系列六位字节码,再按 Base64 规则转换为一串可见字符。VLQ 使用六位比特存储一个编码分组,例如:
在这里插入图片描述
数字 7 经过 VLQ 编码后,结果为 001110,其中:

  • 第一位为连续标志位,标识后续分组是否为同一数字;
  • 第六位表示该数字的正负符号,0为正整数,1为负整数;
  • 中间第 2-5 为实际数值。

这样一个六位编码分组,就可以按照 Base64 的映射规则转换为 ABC 等可见字符,例如上述数字 7 编码结果 001110,等于十进制的 14,按 Base64 字码表可映射为字母 O
在这里插入图片描述

但是,分组中只有中间的 4 个字节用于表示数值,因此单个分组只能表达 -15 ~ 15 之间的数值范围,对于超过这个范围的整数,需要组合多个分组,共同表达同一数字,具体规则:

  • 第一个分组的最后一位为符号位,其它分组从 2-6 均为数值位;
  • 取二进制值最后四位为第一个分组值,之后从后到前,每 5 位划分为一个分组;
  • 除最后一个分组外,其余分组的连续标志位都设置为 1。

例如,对于十进制 -17,其二进制为 10001 (取 17 的二进制) 共 5 位,首先从后到前拆分为两组,后四位 0001 为第一组,连续标志位为 1,符号位为 1,结果为 1,0001,1;剩下的 1 分配到第二个 —— 也是最后一个分组,连续标志位为 0,结果为 0,00001。按 Base64 规则 [100011, 000001] 最终映射为 jA

十进制     二进制               VLQ    Base64
  -17 => 1,0001 => 100011, 000001 =>     jA

同样的,对于更大的数字,例如 1200,其二进制为 10010110000,分组为 [10, 01011, 0000],从后到前编码,第一个分组为 1,0000,0;第二个分组为 1,01011;最后一个分组为 0,00010。按 Base64 映射为 grC

十进制            二进制                     VLQ    Base64
 1200 => 10;01011;0000 => 100000,101011,000010 =>    grC

在这里插入图片描述

结合 VLQ 编码规则,我们再回过头来解读本章开头的例子,对于代码:

编译前编译后
const name = 'tecvan'; console.log(name) /******/ (() => { // webpackBootstrap var __webpack_exports__ = {}; /*!**********************!*\ !*** ./src/index.js ***! \**********************/ var name = 'tecvan'; console.log(name); /******/ })() ; //# sourceMappingURL=main.js.map

编译生成 mappings

;;;;;AAAA,IAAMA,IAAI,GAAG,QAAb;AAEAC,OAAO,CAACC,GAAR,CAAYF,IAAZ,E

按行、片段规则分割后,得出如下片段:

[
  // 产物第 1-5 行内容为 Webpack 生成的 runtime,不需要记录映射关系
  '', '', '', '', '', 
  // 产物第 6 行的映射信息
  ['AAAA', 'IAAMA', 'IAAI', 'GAAG', 'QAAb'], 
  // 产物第 7 行的映射信息
  ['AAEAC', 'OAAO', 'CAACC', 'GAAR', 'CAAYF', 'IAAZ', 'E']
]

以第 6 行 ['AAAA', 'IAAMA', 'IAAI', 'GAAG', 'QAAb'] 为例:

  • AAAA 解码结果为 [000000, 000000, 000000, 000000],即产物第 6 行 0 映射到 sources[0] 文件的 0 0 ,实际对应 varconst 的位置映射;
  • IAAMA 解码结果为 [001000, 000000, 000000, 001100, 000000],即产物第 6 行第 4 列映射到 sources[0] 文件的 0 6 ,实际对应产物 name 到源码 name 的位置映射。

其它片段以此类推,Webpack 生成 .map 文件时,只需要在 webpack-sources 中,按照这个编码规则计算好编译前后的代码映射关系即可。

devtool 规则详解

Webpack 提供了两种设置 Sourcemap 的方式,一是通过 devtool 配置项设置 Sourcemap 规则短语;二是直接使用 SourceMapDevToolPluginEvalSourceMapDevToolPlugin 插件深度定制 Sourcemap 的生成逻辑。

devtool 支持 25 种字符串枚举值,包括 evalsource-mapeval-source-map 等:

devtoolperformanceproductionqualitycomment
(none)build: fastest rebuild: fastestyesbundleRecommended choice for production builds with maximum performance.
evalbuild: fast rebuild: fastestnogeneratedRecommended choice for development builds with maximum performance.
eval-cheap-source-mapbuild: ok rebuild: fastnotransformedTradeoff choice for development builds.
eval-cheap-module-source-mapbuild: slow rebuild: fastnooriginal linesTradeoff choice for development builds.
eval-source-mapbuild: slowest rebuild: oknooriginalRecommended choice for development builds with high quality SourceMaps.
cheap-source-mapbuild: ok rebuild: slownotransformed
cheap-module-source-mapbuild: slow rebuild: slownooriginal lines
source-mapbuild: slowest rebuild: slowestyesoriginalRecommended choice for production builds with high quality SourceMaps.
inline-cheap-source-mapbuild: ok rebuild: slownotransformed
inline-cheap-module-source-mapbuild: slow rebuild: slownooriginal lines
inline-source-mapbuild: slowest rebuild: slowestnooriginalPossible choice when publishing a single file
eval-nosources-cheap-source-mapbuild: ok rebuild: fastnotransformedsource code not included
eval-nosources-cheap-module-source-mapbuild: slow rebuild: fastnooriginal linessource code not included
eval-nosources-source-mapbuild: slowest rebuild: oknooriginalsource code not included
inline-nosources-cheap-source-mapbuild: ok rebuild: slownotransformedsource code not included
inline-nosources-cheap-module-source-mapbuild: slow rebuild: slownooriginal linessource code not included
inline-nosources-source-mapbuild: slowest rebuild: slowestnooriginalsource code not included
nosources-cheap-source-mapbuild: ok rebuild: slownotransformedsource code not included
nosources-cheap-module-source-mapbuild: slow rebuild: slownooriginal linessource code not included
nosources-source-mapbuild: slowest rebuild: slowestyesoriginalsource code not included
hidden-nosources-cheap-source-mapbuild: ok rebuild: slownotransformedno reference, source code not included
hidden-nosources-cheap-module-source-mapbuild: slow rebuild: slownooriginal linesno reference, source code not included
hidden-nosources-source-mapbuild: slowest rebuild: slowestyesoriginalno reference, source code not included
hidden-cheap-source-mapbuild: ok rebuild: slownotransformedno reference
hidden-cheap-module-source-mapbuild: slow rebuild: slownooriginal linesno reference
hidden-source-mapbuild: slowest rebuild: slowestyesoriginalno reference. Possible choice when using SourceMap only for error reporting purposes.

提示:内容摘抄自 Webpack 官网

分开来看都特别晦涩,但这些枚举值内在有一个潜规则:都是由 inlineevalsource-mapnosourceshiddencheapmodule 七种关键字组合而成,这些关键词各自代表一项 Sourcemap 规则,拆开来看:

  1. eval 关键字:当 devtool 值包含 eval 时,生成的模块代码会被包裹进一段 eval 函数中,且模块的 Sourcemap 信息通过 //# sourceURL 直接挂载在模块代码内。例如:
eval("var foo = 'bar'\n\n\n//# sourceURL=webpack:///./src/index.ts?")

eval 模式编译速度通常比较快,但产物中直接包含了 Sourcemap 信息,因此只推荐在开发环境中使用。

  1. source-map 关键字:当 devtool 包含 source-map 时,Webpack 才会生成 Sourcemap 内容。例如,对于 devtool = 'source-map',产物会额外生成 .map 文件,形如:
{
    "version": 3,
    "sources": [
        "webpack:///./src/index.ts"
    ],
    "names": [
        "console",
        "log"
    ],
    "mappings": "AACAA,QAAQC,IADI",
    "file": "bundle.js",
    "sourcesContent": [
        "const foo = 'bar';\nconsole.log(foo);"
    ],
    "sourceRoot": ""
}

实际上,除 eval 之外的其它枚举值都包含该字段。

  1. cheap 关键字:当 devtool 包含 cheap 时,生成的 Sourcemap 内容会抛弃维度的信息,这就意味着浏览器只能映射到代码行维度。例如 devtool = 'cheap-source-map' 时,产物:
{
    "version": 3,
    "file": "bundle.js",
    "sources": [
        "webpack:///bundle.js"
    ],
    "sourcesContent": [
        "console.log(\"bar\");"
    ],
    // 带 cheap 效果:
    "mappings": "AAAA",
    // 不带 cheap 效果:
    // "mappings": "AACAA,QAAQC,IADI",
    "sourceRoot": ""
}

浏览器映射效果:

在这里插入图片描述

虽然 Sourcemap 提供的映射功能可精确定位到文件、行、列粒度,但有时在级别已经足够帮助我们达到调试定位的目的,此时可选择使用 cheap 关键字,简化 Sourcemap 内容,减少 Sourcemap 文件体积。

1 ) module 关键字module 关键字只在 cheap 场景下生效,例如 cheap-module-source-mapeval-cheap-module-source-map。当 devtool 包含 cheap 时,Webpack 根据 module 关键字判断按 loader 联调处理结果作为 source,还是按处理之前的代码作为 source。例如:
在这里插入图片描述
注意观察上例 sourcesContent 字段,左边 devtoolmodule 关键字,因此此处映射的,是包含 class Person 的最原始代码;而右边生成的 sourcesContent ,则是经过 babel-loader 编译处理的内容。

2 ) nosources 关键字:当 devtool 包含 nosources 时,生成的 Sourcemap 内容中不包含源码内容 —— 即 sourcesContent 字段。例如 devtool = 'nosources-source-map' 时,产物:

{
    "version": 3,
    "sources": [
        "webpack:///./src/index.ts"
    ],
    "names": [
        "console",
        "log"
    ],
    "mappings": "AACAA,QAAQC,IADI",
    "file": "bundle.js",
    "sourceRoot": ""
}

虽然没有带上源码,但 .map 产物中还带有文件名、 mappings 字段、变量名等信息,依然能够帮助开发者定位到代码对应的原始位置,配合 sentry 等工具提供的源码映射功能,可在异地还原诸如错误堆栈之类的信息。

1 ) inline 关键字:当 devtool 包含 inline 时,Webpack 会将 Sourcemap 内容编码为 Base64 DataURL,直接追加到产物文件中。例如对于 devtool = 'inline-source-map',产物:

console.log("bar");
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOlsiY29uc29sZSIsImxvZyJdLCJtYXBwaW5ncyI6IkFBQ0FBLFFBQVFDLElBREkiLCJmaWxlIjoiYnVuZGxlLmpzIiwic291cmNlc0NvbnRlbnQiOlsiY29uc3QgZm9vID0gJ2Jhcic7XG5jb25zb2xlLmxvZyhmb28pOyJdLCJzb3VyY2VSb290IjoiIn0=

inline 模式编译速度较慢,且产物体积非常大,只适合开发环境使用。

2 ) hidden 关键字:通常,产物中必须携带 //# sourceMappingURL= 指令,浏览器才能正确找到 Sourcemap 文件,当 devtool 包含 hidden 时,编译产物中不包含 //# sourceMappingURL= 指令。例如:

devtool = 'hidden-source-map'devtool = 'source-map'
/******/ (() => { // webpackBootstrap var __webpack_exports__ = {}; /*!**********************!*\ !*** ./src/index.ts ***! \**********************/ var Person = /** @class */ (function () { }()); /******/ })(); /******/ (() => { // webpackBootstrap var __webpack_exports__ = {}; /*!**********************!*\ !*** ./src/index.ts ***! \**********************/ var Person = /** @class */ (function () { }()); /******/ })(); //# sourceMappingURL=bundle.js.map

两者区别仅在于编译产物最后一行的 //# sourceMappingURL= 指令,当你需要 Sourcemap 功能,又不希望浏览器 Devtool 工具自动加载时,可使用此选项。需要打开 Sourcemap 时,可在浏览器中手动加载:

请添加图片描述

总结一下,Webpack 的 devtool 值都是由以上七种关键字的一个或多个组成,虽然提供了 27 种候选项,但逻辑上都是由上述规则叠加而成,例如:

  • cheap-source-map:代表 不带列映射 的 Sourcemap ;
  • eval-nosources-cheap-source-map:代表 eval 包裹模块代码 ,且 .map 映射文件中不带源码,且 不带列映射 的 Sourcemap。

其它选项以此类推。最后再总结一下:

  • 对于开发环境,适合使用:
    • eval:速度极快,但只能看到原始文件结构,看不到打包前的代码内容;
    • cheap-eval-source-map:速度比较快,可以看到打包前的代码内容,但看不到 loader 处理之前的源码;
    • cheap-module-eval-source-map:速度比较快,可以看到 loader 处理之前的源码,不过定位不到列级别;
    • eval-source-map:初次编译较慢,但定位精度最高;
  • 对于生产环境,则适合使用:
    • source-map:信息最完整,但安全性最低,外部用户可轻易获取到压缩、混淆之前的源码,慎重使用;
    • hidden-source-map:信息较完整,安全性较低,外部用户获取到 .map 文件地址时依然可以拿到源码;
    • nosources-source-map:源码信息缺失,但安全性较高,需要配合 Sentry 等工具实现完整的 Sourcemap 映射。

使用 source-map 插件

上面介绍的 devtool 配置项,本质上只是一种方便记忆、使用的规则缩写短语,Sourcemap 的底层处理逻辑实际由 SourceMapDevToolPluginEvalSourceMapDevToolPlugin 插件实现。

devtool 基础上,插件还提供了更多、更细粒度的配置项,用于满足更复杂的需求场景,包括:

  • 使用 testincludeexclude 配置项过滤需要生成 Sourcemap 的 Bundle;
  • 使用 appendfilenamemoduleFilenameTemplatepublicPath 配置项设定 Sourcemap 文件的文件名、URL 。

使用方法与其它插件无异,如:

const webpack = require('webpack');
module.exports = {
  // ...
  devtool: false,
  plugins: [new webpack.SourceMapDevToolPlugin({
      exclude: ['vendor.js']
  })],
};

插件配置规则较简单,此处不赘述。

总结

综上,Sourcemap 是一种高效的位置映射算法,它将产物到源码之间的位置关系表达为 mappings 分层设计与 VLQ 编码,再通过 Chrome、Safari、VS Code、Sentry 等工具异地还原为接近开发状态的源码形式。

在 Webpack 中,通常只需要选择适当的 devtool 短语即可满足大多数场景需求,特殊情况下也可以直接使用 SourceMapDevToolPlugin 做更深度的定制化。

思考:为什么 Sourcemap 要设计分层结构 + VLQ 编码做行列映射?假设直接记录行列号,会有什么问题?

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

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

相关文章

【话题】IT专业入门,高考假期预习指南

IT专业入门,高考假期预习指南 亲爱的高考学子们, 七月的阳光,如同你们的梦想,炽热而明亮。当你们手中的笔落下最后一道题的答案,那不仅仅是对过去十二年寒窗苦读的告别,更是对未知世界探索的启程号角。你们…

为了SourceInsight从Linux回到Windows

什么是SourceInsight 现在上网搜索这个软件,大多数说他是一个代码阅读软件;但是在官方的说法里面,这是一款支持多语言的编辑器。大概长这样: 看起来十分老旧是吧,但是他其实他已经是第四代了哈哈哈。其实这个软件是我…

c++:动态内存变量

典型的C面向对象编程 元素 (1)头文件hpp中类的定义 (2)源文件cpp中类的实现(构造函数、析构函数、方法) (3)主程序 案例 (1)用C来编程“人一天的生活” (2)“人”的属性:name、age、male (3)“人”的方法:eat、work(coding/shop…

【SSL 1056】最大子矩阵 (多维DP)

题目大意 已知矩阵的大小定义为矩阵中所有元素的和。给定一个矩阵,你的任务是找到最大的非空(大小至少是 1 ∗ 1 1*1 1∗1)子矩阵。 比如,如下 4 ∗ 4 4*4 4∗4 子矩阵 0 -2 -7 0 9 2 -6 2 -4 1 -4 1 -1 8 0 -2 的最大子矩阵是 …

构建LangChain应用程序的示例代码:53、利用多模态大型语言模型在RAG应用中处理混合文档的示例

许多文档包含多种内容类型,包括文本和图像。 然而,在大多数 RAG 应用中,图像中捕获的信息都会丢失。 随着多模态LLMs的出现,比如GPT-4V,如何在RAG中利用图像是值得考虑的。 本篇指南的亮点是: 使用非结…

Airflow: 大数据调度工具详解

欢迎来到我的博客,很高兴能够在这里和您见面!欢迎订阅相关专栏: 欢迎关注微信公众号:野老杂谈 ⭐️ 全网最全IT互联网公司面试宝典:收集整理全网各大IT互联网公司技术、项目、HR面试真题. ⭐️ AIGC时代的创新与未来&a…

国产芯片方案/蓝牙咖啡电子秤方案研发

咖啡电子秤芯片方案精确值可做到分度值0.1g的精准称重,并带有过载提示、自动归零、去皮称重、压低报警等功能,工作电压在2.4V~3.6V之间,满足于咖啡电子秤的电压使用。同时咖啡电子秤PCBA设计可支持四个单位显示,分别为:g、lb、oz、…

stm32——定时器级联

在STM32当中扩展定时范围:单个定时器的定时长度可能无法满足某些应用的需求。通过级联,可以实现更长时间的定时;提高定时精度:能够在长定时的基础上,通过合理配置,实现更精细的定时控制;处理复杂…

Git安装以及环境配置(详细)

一、Git下载 1.官网(但是很慢) https://git-scm.com/ 2.镜像版(比较推荐) CNPM Binaries Mirror 里边多个选择合适的进行下载(不要选带有rc0,rc1的,都是预发布版本) 进入后如下&#xff0c…

【LeetCode】十一、滑动窗口:长度最小的子数组 + 定长子串的元音最大数目

文章目录 1、滑动窗口2、leetcode209:长度最小的子数组3、leetcode1456:定长子串中元音的最大数目 1、滑动窗口 如下,有一个数组,现三个元素为一组,求最大的和,自然可以while循环实现:i 、i1、…

无线领夹麦克风哪个品牌好,推荐口碑最好的麦克风品牌

在5G网络普及的浪潮下,短视频平台的兴起带动了一股全民创作的热潮。无论是城市街头还是乡间小径,人们纷纷拿起手机,记录生活中的点点滴滴。领夹式麦克风凭借其精准的拾音特性和稳定的信号传输,无论是在静止状态还是在移动过程中&a…

【MindSpore学习打卡】应用实践-计算机视觉-SSD目标检测:从理论到实现

在计算机视觉领域,目标检测是一个至关重要的任务。它不仅要求识别图像中的目标物体,还需要精确定位这些物体的位置。近年来,随着深度学习技术的飞速发展,各种高效的目标检测算法层出不穷。SSD(Single Shot MultiBox De…

Elasticsearch 使用误区之二——频繁更新文档

在使用 Elasticsearch 时,频繁更新文档是一种常见误区。这不仅影响性能,还可能导致系统资源的浪费。 理解 Elasticsearch 的文档更新机制对于优化性能至关重要。 关于 Elasticsearch 更新操作,常见问题如下: ——https://t.zsxq.c…

2024年显著性检测部分论文及代码汇总(3)

ICML Size-invariance Matters: Rethinking Metrics and Losses for Imbalanced Multi-object Salient Object Detection code Abstacrt:本文探讨了显著性检测中评价指标的尺寸不变性,尤其是当图像中存在多个大小不同的目标时。作者观察到,…

Elasticsearch集群部署(上)

目录 前言 一. 环境准备 二. 实施部署 三. 安装配置head监控插件 (只在第一台es部署) 四. Kibana部署(当前还是在第一台es部署) 五. 安装配置Nginx反向代理 六. Logstash部署与测试 下篇:Elasticsearch集群部…

汽配企业MES管理系统的四大应用场景

在当今快速迭代的汽车工业领域,一家位于繁华工业园区的中型汽配制造企业正经历着前所未有的变革。该企业,作为汽车发动机零部件的重要供应商,其客户网络遍布国内外,与多家知名汽车制造商保持着紧密的合作关系。然而,随…

WordPress主题大前端DUX v8.7源码下载

全新:用户注册流程,验证邮箱,设置密码 新增:列表显示小视频和横幅视频 新增:文章内容中的外链全部增加 nofollow 新增:客服功能中的链接添加 nofollow 优化:产品分类的价格显示

JavaScript中的this指向

1. 全局环境下的this 在全局环境中(在浏览器中是window对象,在Node.js中是global对象),this指向全局对象。 console.log(this window); // 在浏览器中为true console.log(this.document ! undefined); // true,因为…

测试引擎模拟接口实战

在上一章的内容中,我简单介绍了整个微服务的各个子模块,还封装了一些工具类。 当然,若还没完成上次内容的也可以点击右侧的传送门------传送门 EngineApplication 在开发测试引擎模拟接口之前,还需要给xxx-engine创建一个Sprin…

盛元广通打造智慧校园实验室安全管理系统

盛元广通智慧校园实验室安全管理系统以安全为重点,构建由学校、二级单位、实验室组成的三级联动的实验室安全多级管理体系、多类用户角色,内置教育部标准检查表,支撑实验室相关业务过程的智慧管理。实现通过PC端/手机移动端开展检查工作、手机…