商智C店H5性能优化实战
前言
商智C店,是依托移动低码能力搭建的一个应用,产品面向B端商家。随着应用体量持续增大,考虑产品定位及用户体验,我们针对性能较差页面做了一次优化,并取得了不错的效果,用户体验值(UEI)从一般提升到良好。本文详细记录了优化思路及过程,期望给正在或打算做用户体验提升的小伙伴提供一些参考。
一、性能优化概览
从宏观方面讲,前端性能优化主要包含两个层面:
•快速的首屏响应
指的是从用户输入URL到页面完整渲染出来的过程中,通过减少资源请求时长、合理化页面渲染等方式,让页面内容尽快呈现到用户面前,达到舒适的展示效果。
•流畅的交互体验
指的是在资源加载且页面渲染完成后,用户与页面的交互反馈及时且动效流畅,没有卡顿、掉帧等情况。
本文重点介绍前者,性能监测工具依赖烛龙平台(性能指标来自LightHouse性能工具)。
二、性能分析
1、Lighthouse工具
Lighthouse 是 Google Chrome 推出的一款开源自动化工具,它可以搜集多个现代网页性能指标,分析 Web 应用的性能并生成报告,为开发人员进行性能优化提供参考方向。
1.1 性能指标
•FCP
首次内容绘制(First Contentful Paint),是指测量在用户导航到页面后浏览器呈现第一段 DOM 内容所花费的时间。DOM 内容包括页面上的图像、非白色元素和 SVG 等,不包括 iframe 内的任何内容。
•LCP
最大内容绘制(Largest Contentful Paint):测量视口中最大的内容元素何时呈现到屏幕上,这近似于页面的主要内容对用户可见的时间。
•SI
速度指数(Speed Index),反映了网页内容填充的速度。页面解析渲染过程中,资源的加载和主线程执行的任务会影响到速度指数的结果。
•CLS
累积布局偏移(Cumulative Layout Shift),主要测量可见元素在可视区域内的移动情况。该指标需要重点关注,随着Lighthouse的版本迭代,该指标占比一直呈上升趋势,也是页面性能优化容易忽略的方面。以下为Lighthouse不同版本中CLS指标的占比情况:
•TBT
总阻塞时间(Total Blocking Time),是指测量页面被阻止响应用户输入(例如鼠标点击、屏幕点击或键盘按下)的总时间。它是通过添加 FCP 和 TTI 之间所有长任务的阻塞部分来计算总和,任何执行时间超过 50 毫秒的任务都是长任务。
各指标表现评价标准:
1.2 UEI计算规则
UEI指的是用户体验值,烛龙平台底层使用的是Lighthouse性能统计工具。其中,单页面的得分统计规则与其保持一致(性能指标分数的加权平均值)。针对多页面应用,整体评分计算规则为,每个页面得分的加权平均值:(页面A * A访问量 + 页面B * B访问量 …)/ (A访问量 + B访问量 + …)。
2、Chrome调试工具
Chrome的Performance面板,可以记录页面加载时\运行时的所有活动,方便我们找出页面的性能瓶颈。
以上为performance面板的概览图,通过对页面加载过程的录制,查看视图面板的主线程工作过程,我们能够找到页面阻塞的长任务,从而优化TBT指标;交互阶段存在的动画卡顿等问题,也可以通过该面板进行分析和优化。
三、实战
1、项目介绍
商智C店,是依托移动低码搭建的面向B端商家的应用。根据烛龙数据统计,优化之前,用户体验值在58分左右。我们期待通过本次优化,将烛龙统计得分提升到体验良好的水平(75分及以上)。从下图可以看出,页面的CLS、TBT分数很低,LCP指标分数位于性能良好与性能较差之间,这三个指标是我们接下来进行优化的重点。
2、过程记录
2.1 减小资源体积
2.1.1 抽取公共依赖
商智C店采用了主应用加三个微应用的架构,这三个微应用的包大小为:
可以发现,每个包的体积都很大(5000k以上),这势必会影响资源下载速度并拖慢代码执行效率。微应用包体积过大的原因是:主应用和多个微应用间存在重复打包,如组件库(自研)、公共库依赖(react、react-dom、echarts)等内容。
针对该问题,可在制品的生成阶段做处理:生成两个包,一为完整的包,保证其能够独立使用;二为优化的包,里面剔除了公共依赖及组件库的样式。调整后,包的体积减少1300多k,总包大小减少至4000k左右。
需要说明的是,自研组件库目前并没有提供UMD格式打包方式,因此以上提到的公共依赖不包含自研组件库相关的包(后续会处理)。
2.1.2 tree shaking优化
tree shaking(摇树) ,用于描述移除 JavaScript 上下文中的未引用代码(dead-code)。最初起源于 ES2015 模块打包工具 rollup。
自研组件库主要包含三个包,PC组件库jmtd、移动组件库jmtm、jmtd-hooks库。其中hooks库是对两端组件库的二次封装,帮助低码平台处理组件间的逻辑编排功能,三个库均通过npm包的方式引入。
排除公共依赖及样式后,微应用制品的体积大约在4000k左右,这显然还不是一个理想值。打包构建工具依赖webpack5,根据webpack性能分析插件分析,定位到jmtd-hooks包的体积过大。按照固有思维,webpack5在生产环境默认支持tree shaking,因此生成的制品只会打包使用到的代码,并不会引起制品的体积过大。那么问题出在哪里呢?
原因在于,jmtd-hooks库的打包方式有问题。因hooks包较强的业务属性,我们将原始文件打包成了一个文件。
webpack的tree shaking有两种方式:
•usedExports:开启该配置后,能够在打包环节找到未被使用且无副作用的函数且不会对其打包。 它只针对单文件生效,不能跨文件进行分析。而js是一门动态语言,因其灵活多变的特性,编译工具很难准确分析某个函数是否具有副作用,因此其优化能力较弱。
•sideEffects:具有跨文件分析能力,如果某个库的package.json中配置了sideEffects为true,表明该库中的所有文件都没有副作用。若某文件中的方法未被使用,编译工具可放心的进行摇树,其优化能力更强。
分析后可得出结论:webpack对单文件,仅利用其静态分析能力摇树效果很弱,导致微应用制品包含了大量未使用的代码。解决办法也很简单,调整jmtd-hooks的打包方式,保留原始的文件结构。调整后hooks包的结构为:
可看到,制品体积有了大幅的减小,最终控制在2000k以下。经过抽取公共依赖和摇树优化两个步骤,整体包体积减少**65%**左右。
2.1.3 删除项目冗余代码
随着需求持续迭代,项目中很容易存在一些无效的脚本及样式引用,或者一些不规范的写法,如未使用的全局变量、没有意义的console等,都需要进行删除,保持代码的精简性。
完成以上步骤后,我们进行了一次上线,并连续监测了一周的数据。用户体验值有了明显的提升,从以前的58分提升到65分。
优化前:
优化后:
以下为优化前后各指标的对比数据(单位:ms):
2.2 优化资源加载速度
一个页面从输入URL到最后在浏览器的渲染流程大致如下:
URL解析 => DNS解析 => 建立TCP连接 => 客户端发送请求 => 服务器处理和响应请求 => 浏览器解析并渲染响应内容 => 断开TCP链接
从URL解析到服务器响应请求的过程属于网络层面,常用的优化手段包括:
1、缓存技术:合理的使用缓存,如CDN缓存、浏览器缓存等,来加快资源的下载速度。
2、文件压缩合并:通过压缩工具减少资源大小,多个文件合并成一个文件,减少网络请求开销。
3、开启gzip压缩:在文件传输阶段,开启gzip压缩,减小数据传输量,节省服务器网络带宽。
4、http2协议:该协议带来了很多新的特性,如二进制分帧、头部压缩等,把证文件传输更加安全高效。
5、DNS预解析:初次请求某个跨域域名,需先解析该域名,其解析时间很容易被忽视,DNS预解析能够减少用户等待的时间。
6、域名分片:域名分片指的是将同一站点下的静态资源分布在不同域名下,其最大的好处是,能够突破浏览器下载资源的并发限制。
7、代码分割:将整个应用代码合理分割成多个部分,能够有效减小首屏资源的请求体积,提升资源下载速度。
2.2.1 代码分割
合理的分割代码,能够有效加快首屏资源请求速度。出于此考虑,我们将项目结构分为了一个主应用加三个微应用的模式,主应用作为基座来处理导航及微应用间通信,三个微应用(经营分析、行业竞争、我的关注)作为独立模块,承接细分的业务功能。以模块划分代码,大体上解决了问题,但针对某些高频使用的详情页,还有进一步优化的空间。
根据埋点数据统计,用户高频使用的主要有两个页面:经营分析页和指标详情页,其访问的PV值占到了90%以上。经营分析页的表现尚可,用户体验值在70分左右,可暂不优化;指标详情页的表现堪称灾难,仅得到58分,明显低于现阶段65分的平均值。
分析原因:指标详情页为一个二级路由页面,可通过核心指标页下钻到该页,也可通过客户端首页直接查看某个指标的详情页。这将导致,在查看该页面前,需先加载经营分析模块。
解决思路:将指标详情页独立为一个微应用,单独维护。当用户通过京麦客户端直接访问某个指标的详情时(用户使用此场景频率很高),只加载该微应用代码,避免一级路由页代码的影响。
优化后效果很明显,指标详情页得分从58分直接飙升到80分,各个维度的指标都有了不错的提升。
2.2.2 资源预加载
资源预加载是性能优化的常用手段,针对模块较多的应用尤其有效。前文我们已将商智C店分割为主应用加三个微应用的代码结构,首页加载的是主应用加经营分析模块,当用户切换其它的模块(竞争分析、我的关注等),需要先下载该模块的制品(2000k左右),再进行内容的渲染。
采用资源预加载方案,可在首页内容加载完成后,利用浏览器的空余资源,预加载其它模块的文件,当用户切换到其它模块时,资源已经提前加载完毕,省去资源下载的时间。
具体实现逻辑为:
// 通过动态创建script的方式,预加载文件
// 脚本加载并解析完成后,会将执行逻辑挂载到全局变量上
function loadScript (url) {if (!cache || cache[url]) return;cache[url] = new Promise(resolve => {const script = document.createElement('script');script.src = url;script.onload = () => {document.body.removeChild(script);resolve(window.__microApp__);};document.body.appendChild(script);});
}// 当页面加载完成后,通过requestIdleCallback方法,利用浏览器空余资源来预加载文件
window.onload = function () {requestIdleCallback(() => {microAppArr.forEach(({ src }) => loadScript(src));});
};
资源预加载之前,行业竞争模块的得分在60分,优化之后,提升到了68分:
优化之前,我的关注模块的得分在65分,优化之后提升到72分:
2.2.3 DNS预解析
当你的网站第一次请求某个跨域域名时,需要先解析该域名(例如页面访问cdn资源,第一次访问需要先解析cdn),而在该请求之后的请求都没有这项时间支出。典型的一次DNS解析需耗费20-120毫秒,其解析的时间很容易被忽视。DNS Prefetching 是具有此属性的域名,不需要用户点击链接就在后台解析,这个方式能减少用户的等待时间,提升用户体验。
<!-- 用meta信息来告知浏览器, 当前页面要做DNS预解析 -->
<meta http-equiv="x-dns-prefetch-control" content="on" />
<!-- 在页面header中使用link标签来强制对DNS预解析 -->
<link rel="dns-prefetch" href="xxx.com">
商智C店具体应用案例:
2.2.4 域名分片
域名分片指的是将同一站点下的静态资源分布在不同域名下。例如:主站域名 www.a.com;图片域名 www.a-img.com;脚本、样式等文件的域名 www.a-link.com。其最大的好处是,能够突破浏览器下载资源的并发限制,具体可参考文章。
同样在商智C店中,我们也应用了该思路,如将React、Echarts等公共库、业务打包代码、图片等静态资源分别放在不同的CDN域名,从而突破浏览器的并发请求限制。
2.2.4 雪碧图
主应用的底部是一个菜单导航,它的图标包含了6张图片(选中和非选中态使用不同图片),一个合理的方式是,使用雪碧图(Sprite),将多个连续的图片合并为一张,通过改变背景图位置来控制图片显示。
2.3 优化用户感知
2.3.1 滚动加载
微应用模块的展示形式为橱窗卡片组成的长列表(10个左右,后续需求迭代还会增加)。橱窗卡片作为基础的布局组件,承接了筛选区域、下钻功能、可视化组件的展示功能,如果在首屏一次加载太多,将会导致较大的渲染压力。
滚动加载是提升首屏渲染性能的很好方案,它的核心是判断目标元素(橱窗卡片)是否在可视区域范围内,当其不可见时,只需在卡片内容区渲染一个有默认高度的占位元素,同时也不必加载筛选区域组件,当用户滚动到该区域时,再渲染业务相关的内容。
如图所示,首屏只需渲染核心指标和目标监控两个橱窗卡片的内容,其余卡片只渲染一个占位元素,有效缓解浏览器的渲染压力。那么具体逻辑是怎么实现的呢?
通常有两种方式可判断元素是否在可视范围内:
1、监听scroll事件,获取目标元素(橱窗卡片)相对于视口的坐标,再判断其是否在可视区域内。该方法的缺点是,scroll事件密集触发,容易造成性能问题。
2、IntersectionObserver API,翻译为”交叉观察器“,可以自动"观察"元素是否可见,Chrome 51+ 支持。
这里我们采用第二种方案,初始状态设置内容区域不可见,当元素挂载完成后,创建io监听器,监听到卡片位于可视范围内,再加载对应组件,具体逻辑参考以下代码。
function WindowCard ({ title, filter, children }) {const wcRef = useRef(null);// 初始状态,默认设置内容区域不可见const [visible, setVisible] = useState(!useObserver);useEffect(() => {// 元素挂载后,创建io监听器const io = new IntersectionObserver(entries => {if (entries[0].intersectionRatio <= 0) return;// 当元素位于可视区域范围内后,加载业务组件setVisible(true);// 业务组件加载后,断开监听io.unobserve(wcRef.current);});io.observe(wcRef.current);return () => {io.disconnect();};}, []);return (<div className='window-card' ref={wcRef}>// 省略head部分逻辑<div className='window-card-content'>{visible ? children : <div style={{ height: 200 }} />}</div></div>);
}
2.3.2 优化CLS指标
根据LightHouse统计数据,CLS指标得分值很低,其反映了在首屏页面加载时,出现了较大的布局偏移。
类似于核心指标卡片,在指标卡加载前,内容区域高度为0,而loading加载后,有一个200px的占位高度,真实的指标卡渲染出来后,高度变为322px,用户能够感觉到明显的抖动。
还有指标详情页中的场景,在指标卡loading阶段,占位高度为200px,而真实渲染的指标卡的高度为142px。假如用户在此时点击某个可点击区域,很容以造成误触,带来很差的用户体验。
诸如以上的场景,我们事先能够确定指标卡渲染出来的真实高度,可以提前将其固定。参照类似的方法,检查其他的页面,能够尽量避免页面首屏的抖动。
3、实战总结
通过抽取公共依赖和摇树优化,微应用的体积从5000多k减小到2000k以内,应用体验值从58分提升到65分。通过对长列表页面适配滚动加载,提升了页面的渲染效率;固定首屏指标卡等元素的高度,减少了页面布局偏移,从而保证页面稳定的显示效果;将用户高频使用页面(指标详情页)独立为微应用,直接将拖后腿的页面变成性能表现优秀的页面;资源预加载,充分利用了浏览器的空余资源,有效提高页面加载速度。应用的体验值,从65分提升到75分:
优化前:
优化后:
细分指标的表现都有了明显提升,以下为优化前后的对比数据:
本次优化的重点是提升商智C店首屏显示的效果,目标是将烛龙统计得分提升到体验良好的水平(75分及以上),基本完成了预定目标。因优化过程位于需求迭代的间隙,并不计划对系统架构及业务代码进行深度调整,因此还有些遗留工作放到了后续:如微应用的体积仍有进一步优化的空间、TBT指标得分虽有提升,但表现仍较差、某些组件交互动效卡顿等。
最后,期望本文的经验能给同样在做性能优化的小伙伴一些参考,文章的不足之处,可在评论区讨论。敬请期待后续移动端交互优化的文章。
作者:京东零售 郄鹏飞
来源:京东云开发者社区 转载请注明来源
相关文章:
商智C店H5性能优化实战
前言 商智C店,是依托移动低码能力搭建的一个应用,产品面向B端商家。随着应用体量持续增大,考虑产品定位及用户体验,我们针对性能较差页面做了一次优化,并取得了不错的效果,用户体验值(UEI&…...
Unity 使用 Plastic 同步后,正常工程出现错误
class Newtonsoft.Json.Linq.JToken e CS0433:类型"JToken"同时存在于"Newtonsoft.Json.Net20,Version3.5.0.0,Cultureneutral,,PublicKeyToken30ad4fe6b2a6aeed"和"Newtonsoft.Json, Version12.0.0.0,Cultureneutral,PublicKeyToken30ad4fe6b2a6aeed…...
详细设计文档该怎么写
详细设计文档是软件开发过程中的一个关键阶段,它为每个软件模块的实现提供了详细说明。这份文档通常在概要设计阶段之后编写,目的是指导开发人员如何具体实现软件的功能。以下是撰写详细设计文档的步骤和一些示例: 步骤和组成部分 引言 目的…...
集团企业OA办公协同平台建设方案
一、企业对协同应用的需求分析 实现OA最核心、最基础的应用 业务流转:收/发文、汇报、合同等各种审批事项的业务协作与办理 信息共享:规章制度、业务资料、共享信息资源集中存储、统一管理 沟通管理:电子邮件、手机短信、通讯录、会议协作等…...
Spring Security之认证
系列文章目录 提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加 Spring Security之认证 提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 系列文章目录前言一、什么是Spring…...
智能语音机器人NXCallbot
受出海公司业务全球化的影响,智能客服逐渐从便捷应用变为市场刚需。新基建七大领域中,人工智能及场景应用的基础建设是最核心的领域,而智能客服作为商业化实际应用的核心场景之一,能提升企业运营效率,为行业客户赋能。…...
Vue 3中toRaw和markRaw的使用
Vue 3的响应性系统 在Vue 3中,响应性系统是构建动态Web应用程序的关键部分。Vue使用响应性系统来跟踪依赖关系,使数据更改能够自动更新视图。这使得Vue应用程序在数据变化时能够高效地更新DOM。Vue 3引入了新的Proxy对象来替代Vue 2中的Object.definePro…...
移动神器RAX3000M路由器不刷固件变身家庭云之三:外网访问家庭云
本系列文章: 移动神器RAX3000M路由器变身家庭云之一:开通SSH,安装新软件包 移动神器RAX3000M路由器变身家庭云之二:安装vsftpd 移动神器RAX3000M路由器变身家庭云之三:外网访问家庭云 移动神器RAX3000M路由器变身家庭云…...
基于多反应堆的高并发服务器【C/C++/Reactor】(中)线程池的启动和从线程池中取出一个反应堆实例
一、线程池的启动 (主线程) // 启动线程池 (主线程) void threadPoolRun(struct ThreadPool* pool) {/*线程池被创建出来之后,接下来就需要让线程池运行起来,其实就是让线程池里的若干个子线程运行起来*//…...
go语言gin框架的基本使用
1.首先在linux环境上安装go环境,这个网上搜搜就行 2.初始化一个go mod,网上搜搜怎么初始化 3.下面go代码的网址和端口绑定自己本机的就行 4.与另一篇CSDN一起食用,效果更好哟---> libcurl的get、post的使用-CSDN博客 package mainimpo…...
TypeScript 从入门到进阶之基础篇(六) 类型(断言 、推论、别名)| 联合类型 | 交叉类型
系列文章目录 TypeScript 从入门到进阶系列 TypeScript 从入门到进阶之基础篇(一) ts基础类型篇TypeScript 从入门到进阶之基础篇(二) ts进阶类型篇TypeScript 从入门到进阶之基础篇(三) 元组类型篇TypeScript 从入门到进阶之基础篇(四) symbol类型篇TypeScript 从入门到进阶…...
Linux操作系统基础(14):文件管理-文件属性命令
1. 查看文件属性 stat命令用于显示文件的详细信息,包括文件的权限、所有者、大小、修改时间等。 #1.显示文件信息 stat file.txt#2.显示文件系统状态 stat -f file.txt#3.显示以时间戳的形式文件信息 stat -t file.txt2. 修改文件时间戳 touch命令用于创建新的空…...
metaSPAdes,megahit,IDBA-UB:宏基因组装软件安装与使用
metaSPAdes,megahit,IDBA-UB是目前比较主流的宏基因组组装软件 metaSPAdes安装 GitHub - ablab/spades: SPAdes Genome Assembler #3.15.5的预编译版貌似有问题,使用源码安装试试 wget http://cab.spbu.ru/files/release3.15.5/SPAdes-3.15.5.tar.gz tar -xzf SP…...
Apache、MySQL、PHP编译安装LAMP环境
1. 请简要介绍一下LAMP环境。 LAMP环境是一个在Linux操作系统上搭建的服务器环境组合,由Apache、MySQL、PHP三种软件构成。这种环境是开源的,跨平台的,并且由于各组件经常一起使用,因此具有高度的兼容性。 其中,Apac…...
L1-087:机工士姆斯塔迪奥
题目描述 在 MMORPG《最终幻想14》的副本“乐欲之所瓯博讷修道院”里,BOSS 机工士姆斯塔迪奥将会接受玩家的挑战。 你需要处理这个副本其中的一个机制:NM 大小的地图被拆分为了 NM 个 11 的格子,BOSS 会选择若干行或/及若干列释放技能&#x…...
如何做一个炫酷的Github个人简介(3DContribution)
文章目录 前言3D-Contrib第一步第二步第三步第四步第五步第六步 前言 最近放假了,毕设目前也不太想做,先搞一点小玩意玩玩,让自己的github看起来好看点。也顺便学学这个action是怎么个事。 3D-Contrib 先给大家看一下效果 我的个人主页&am…...
基于单片机的护理床控制器设计
一、摘要 随着科技的不断发展,人们对生活质量的要求越来越高,特别是在医疗保健领域。护理床作为医院病房中常见的设备,其功能和性能直接影响到患者的康复进程。本文主要介绍了一种基于单片机的护理床控制器设计,该控制器可以实现…...
《3D数学基础-图形和游戏开发》阅读笔记 | 3D数学基础 (学习中 1.6更新)
文章目录 3D数学基础矢量/向量什么是向量点与矢量的关系 向量基础运算 向量加法向量基础运算 数乘 线性组合 - 坐标系的基如果选择不同的基向量会怎么样?- 张成(Span)的空间三维向量的张成空间线性相关与线性相关 矩阵与线性变换矩阵-几何意义线性变换矩阵乘法与线性…...
解锁测试性能瓶颈:深度探讨JMeter分布式性能测试!
在做后端服务器性能测试中,我们会经常听到分布式。但你是否了解分布式呢?今天,我们就来给大家讲讲,在企业实战中,如何使用分布式进行性能测试,实战过程中,又有哪些地方要特别注意? 0…...
SiC电机控制器(逆变器)发展概况及技术方向
SiC电机控制器(逆变器)发展概况及技术方向 1.概述2.电动汽车动力系统设计趋势3.栅极驱动器和驱动电源配置4.结论 tips:资料来自网上搜集,仅供学习使用。 1.概述 2022年到2023年,第三代半导体碳化硅被推上了新的热潮。…...
useContext
可以跨组件传值 其实主要的就是三步 1、const xxx React.createContext();创建一个context 2、<xxx.Provider value{{ num, setNum }}>父组件设置要传递的值 3、const { num, setNum } React.useContext(xxx);子组件下使用 特点: 1、可以有多个xxx.Pr…...
Java数据结构:1. 数据结构前置知识
文章目录 一、初识数据结构二、初识集合框架1. 什么是集合框架2. 集合框架的重要性3. 背后所涉及的数据结构以及算法 三、时间复杂度空间复杂度1. 算法效率2. 时间复杂度(1)概念(2)大O的渐进表示法(3)推导大…...
Vue中使用Element UI的Table组件实现嵌套表格(最简单示例)
以下是一个简单的示例代码,演示如何在Vue中使用Element UI的Table组件实现嵌套表格: html <template><div><el-table :data"tableData" style"width: 100%"><el-table-column prop"name" label&quo…...
如何使用RESTful API构建 web 应用程序
RESTful API 是一种设计风格,用于构建可扩展、灵活和可维护的 web 应用程序。它是一种基于 HTTP 协议的架构风格,旨在提供一组规范和约束,以便客户端和服务器之间的通信更加简单和可预测。 RESTful API 通过使用 HTTP 动词来定义资源的操作&…...
开启Android学习之旅-4-Android集成FontAwesome
FontAwesome 是一个非常标准、统一风格的图标库。产品经理在原型中应用了很多图标都是FontAwesome。正常流程是 UI 需要再手工绘制或在 iconfont 或 iconpark 网站挨个找,如果在 Android 直接使用不是省了一步(注意版权问题,使用免费版&#…...
Qt——TCP UDP网络编程
目录 前言正文一、TCP二、UDP1、基本流程2、必备知识 三、代码层级1、UDP服务端 END、总结的知识与问题1、如何获取QByteArray中某一字节的数据,并将其转为十进制?2、如何以本年本月本日为基础,获取时间戳,而不以1970为基础&#…...
有什么安全处理方案可以有效防护恶意爬虫
常见的爬虫 有百度爬虫、谷歌爬虫、必应爬虫等搜索引擎类爬虫,此类爬虫经常被企业用于提高站点在搜索引擎内的自然排名,使得站点在各大搜索引擎中的排名能够提高,进一步通过搜索引擎来进行引流为企业增加业务流量。 恶意爬虫与合法、合规的搜…...
Flutter3.X基础入门教程(2024完整版)
Flutter介绍: Flutter是谷歌公司开发的一款开源、免费的UI框架,可以让我们快速的在Android和iOS上构建高质量App。它最大的特点就是跨平台、以及高性能。 目前Flutter已经支持 iOS、Android、Web、Windows、macOS、Linux的跨平台开发。 教程所讲内容支持…...
GEE——土地利用分类种两个矢量集合中不同列进行相减的方式(利用join进行连接处理)
问题: 我有两个具有相同 ID 的特征集,我想从第二个特征集中减去第一个特征集的表格单元格。 我使用了这个函数,但它计算的是表 1 中第一个元素与表 2 中其他元素的减法。 我想逐个单元格计算减法。第一个表格中 id 为 1 的单元格减去第二个表格中 id 为 1 的单元格,2x2、…...
mnn-llm: 大语言模型端侧CPU推理优化
在大语言模型(LLM)端侧部署上,基于 MNN 实现的 mnn-llm 项目已经展现出业界领先的性能,特别是在 ARM 架构的 CPU 上。目前利用 mnn-llm 的推理能力,qwen-1.8b在mnn-llm的驱动下能够在移动端达到端侧实时会话的能力,能够在较低内存…...
网站制作背景/seo外链友情链接
错误的提示内容为: 解决方案: 其实这是系统权限的问题,它的导致可能是由于重装了系统,或者从别的地方(如,当时在另外一台电脑上该数据库已经通过安全的方式附加到了SQL Server中)直接拷贝过来,而…...
b2b网站论文/百度推广哪家做的最好
Lua是个面向过程的语言, 但通过Metatable可以模拟出面向对象的样子. 其关键就在于__index这个域. 他提供了表的索引值入口. 这很像重写C#中的索引器, 当表要索引一个值时如table[key], Lua会首先在table本身中查找key的值, 如果没有并且这个table存在一个带有__index属性的Meta…...
成都科技网站建设联系/重庆百度快照优化
1. 前言 自1994年由爱立信推出至今,蓝牙技术已经走过了20个岁月。从最初的Bluetooth V1.0,到Bluetooth V4.0(最新的为V4.1,2013年底发布),经历了近9个版本的修订后,发展为当前的状况。 说实话&a…...
汽车网站大全汽车网/seo推广优化
BGP进程 输入输出进程(BGP I/O):它为TCP和BGP之间提供了一个接口。(1)它从TCP套接字(socket)中读取消息,并把它们放到BGP输入队列,以便被BGP Router进程操作;(2)积聚在输出中的消息也…...
做商业网站/seo搜索优化软件
有时候我们需要跟踪一个类的对象个数,又不想为每一个类去实现引用计数,我们可以使用继承思维去实现这一目标。 #include "stdafx.h" #include <iostream> using namespace std; class Counted { private:static int count; public:Cou…...
南阳美容网站建设/百度一下你知道主页官网
int StepJudge(int oldx,int oldy,int nowx,int nowy)/* oldx,oldy 棋字原来位置 *//* oldx,oldy 棋字新位置 *//* 判断从原位置到新位置的合法性 */{int index,count0;int nox,noy;int x,y,x1,x2,y1,y2;BYTE ChessId; /* 棋字是哪一方的,有RED,BLUE&…...