性能优化之FPS实践报告。
环境:Xcode 9.3
iPhone 7p 11.3
依赖 : masonry + SDWebimage
本文章主要探讨以下几个对FPS的影响:
1.Color Blended layers (混合图层),Color Misaligned Images(image对齐), Color off-screen render(离屏渲染)
2.masonry,flexlib,AsyncDisplayKit,frame等性能对比(这个不在文中讨论见https://draveness.me/layout-performance),如果对
性能要求极为苛刻的需要定夺frame和auto layout之间的平衡点,每个都有利弊.
xcode 9.3 的instrument 中对 core animation的debug options进行了移除,这个在官网中也有了说明。
Deprecation and Removal Warnings
The Core Animation instrument and template have been deprecated in Instruments. The functionality previously under "Debug Options" has moved to Xcode, under "Debug > View Debugging > Rendering". (22971414)
The OpenGL ES Analyzer Instrument is no longer supported. It has been replaced by the GPU Frame Debugger in Xcode and will be removed in a future version of Instruments. (35104029)
General
功能被移到了Xcode的 Debug->View debugging -> Rendering下了。以后调这几个不需要再打开CA 了,只有监控FPS时打开观察。
解决blended layer问题。
红色部分是因为UILabel透明背景,对于图片UIImageView的是因为UIImage本身是带了alpha通道。所以在渲染时显示红色。
对于label
///对lable处理blended layers
- (void)settingLabelCleanBlended
{
self.lb_title.backgroundColor = [UIColor whiteColor];
self.lb_title.layer.masksToBounds = YES;
}
对于image的,可以让UI设计的时候设计为不透明。(后面看源码,我通过源码的方式改变alpha通道设至)
经过处理
///clean blended layers
[self settingLabelCleanBlended];
[self settingAvatar];
经过处理后看到不透明的时候QQ头像显示为黑色边框。
解决Color Misaligned Images 这个一般都是图片大小和设定的imageview的宽高不一致所致,调到一致就OK.
如果用模拟器调试则需要开启光栅设置,(真机不用。)
///光栅
- (void)settingeRasterize
{
CGFloat scale = [UIScreen mainScreen].scale;
self.avatar.layer.shouldRasterize = YES;
self.avatar.layer.rasterizationScale = scale;
self.pic.layer.shouldRasterize = YES;
self.pic.layer.rasterizationScale = scale;
self.lb_title.layer.shouldRasterize = YES;
self.lb_title.layer.rasterizationScale = scale;
}
处理后效果为
最后解决离屏渲染,其实就是前面的settingeRasterize中的 这几个设置。
先看源码,看完后,再继续分晰,前前后后的FPS执行的差距,看有多少提升。
cell.h
#import <UIKit/UIKit.h>@interface testCell : UITableViewCell
@property (nonatomic , strong) UIImageView *avatar;
@property (nonatomic , strong) UIImageView *pic;
@property (nonatomic , strong) UILabel *lb_title;- (void)loadDataSet:(id)dataset;
@end
cell.m
//
// testCell.m
// fengsh
//
// Created by fengsh on 2017/4/8.
// Copyright © 2017年 All rights reserved.
//#import "testCell.h"@interface testCell()
@property (nonatomic, strong) UIView *alignview;
@end@implementation testCell- (void)awakeFromNib {[super awakeFromNib];// Initialization code
}- (void)setSelected:(BOOL)selected animated:(BOOL)animated {[super setSelected:selected animated:animated];// Configure the view for the selected state
}- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];if (self) {[self createControls];[self layoutControls];}return self;
}- (void)createControls
{self.alignview = [[UIView alloc]init];[self.contentView addSubview:self.alignview];self.avatar = [[UIImageView alloc]init];self.avatar.image = [UIImage imageNamed:@"share_QQ"];//132 * 132 ,3倍图 所以一倍时为44[self.alignview addSubview:self.avatar];self.pic = [[UIImageView alloc]init];[self.alignview addSubview:self.pic];self.lb_title = [[UILabel alloc]init];self.lb_title.numberOfLines = 0;self.lb_title.font = [UIFont systemFontOfSize:14];self.lb_title.textColor = [UIColor blackColor];[self.alignview addSubview:self.lb_title];///clean blended layers[self settingLabelCleanBlended];[self settingAvatar];///使用光栅
// [self settingeRasterize];}- (void)layoutControls
{[self.avatar mas_makeConstraints:^(MASConstraintMaker *make) {make.top.leading.equalTo(20);make.height.width.equalTo(44); //132 / 3}];[self.lb_title mas_makeConstraints:^(MASConstraintMaker *make) {make.top.equalTo(20);make.leading.equalTo(self.avatar.mas_trailing).offset(10);make.trailing.equalTo(self.pic.mas_leading).offset(-10);make.height.greaterThanOrEqualTo(20).priorityHigh();make.bottom.equalTo(-20).priorityLow();}];[self.pic mas_makeConstraints:^(MASConstraintMaker *make) {make.top.equalTo(20);make.trailing.equalTo(-20);make.width.equalTo(108);make.height.equalTo(72);}];[self.alignview mas_makeConstraints:^(MASConstraintMaker *make) {make.top.leading.trailing.equalTo(0);make.height.greaterThanOrEqualTo(132);make.bottom.equalTo(0);}];
}///圆角
- (void)settingAvatarRadius
{self.avatar.layer.cornerRadius = 22;self.avatar.layer.masksToBounds = YES;
}///光栅
- (void)settingeRasterize
{CGFloat scale = [UIScreen mainScreen].scale;self.avatar.layer.shouldRasterize = YES;self.avatar.layer.rasterizationScale = scale;self.pic.layer.shouldRasterize = YES;self.pic.layer.rasterizationScale = scale;self.lb_title.layer.shouldRasterize = YES;self.lb_title.layer.rasterizationScale = scale;
}- (void)settingAvatar
{//share_QQself.avatar.image = [self CGContextClip:[UIImage imageNamed:@"share_QQ"] cornerRadius:22 backgroundColor:[UIColor whiteColor]];
// self.avatar.image = [self UIBezierPathClip:[UIImage imageNamed:@"share_QQ"] cornerRadius:22 backgroundColor:[UIColor whiteColor]];
}///对lable处理blended layers
- (void)settingLabelCleanBlended
{self.lb_title.backgroundColor = [UIColor whiteColor];self.lb_title.layer.masksToBounds = YES;
}- (void)loadDataSet:(id)dataset
{self.lb_title.text = @"好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字";[self.pic sd_setImageWithURL:[NSURL URLWithString:@"https://images.ihuoqiu.com/article/2018/04/07/huoqiuwang_201804072024469924.png"] placeholderImage:nil completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {dispatch_async(dispatch_get_global_queue(0, 0), ^{UIImage *scaleimg = image;CFTimeInterval start = CFAbsoluteTimeGetCurrent();scaleimg = [self useWay1:image]; //方式一
// scaleimg = [self useWay2:image]; //方式二
// scaleimg = [self useWay3:image]; //方式三CFTimeInterval end = CFAbsoluteTimeGetCurrent();CFTimeInterval timeval = end - start;NSLog(@"毫时 %f ms",timeval * 1000);dispatch_async(dispatch_get_main_queue(), ^{self.pic.image = scaleimg;});[self lookImageInfo:scaleimg];});}];
}- (UIImage *)useWay1:(UIImage *)srcimage
{return [self scaleImage:srcimage toSzie:CGSizeMake(108, 72)];
}- (UIImage *)useWay2:(UIImage *)srcimage
{return [self scaleImageWithData:UIImageJPEGRepresentation(srcimage, 1.0) toSize:CGSizeMake(108, 72) scale:0 orientation:UIImageOrientationUp];
}- (UIImage *)useWay3:(UIImage *)srcimage
{return [self createRGBAWithUIImage:srcimage toSize:CGSizeMake(108, 72) opaque:YES];
}#pragma mark - 图片处理方法/*如果包含 alpha ,那么每个颜色分量是否已经乘以 alpha 的值,这种做法可以加速图片的渲染时间,因为它避免了渲染时的额外乘法运算。比如,对于 RGB 颜色空间,用已经乘以 alpha 的数据来渲染图片,每个像素都可以避免 3 次乘法运算,红色乘以 alpha ,绿色乘以 alpha 和蓝色乘以 alpha带last 说明alpha 分量是在RGB后面即RGBA格式,带first 说明alpha 分量是在RGB前面即ARGB格式typedef CF_ENUM(uint32_t, CGImageAlphaInfo) {kCGImageAlphaNone, //不带alpha,即不透明kCGImageAlphaPremultipliedLast, //带alpha通道,图片解码压缩的时候,就将 alpha 通道的值分别乘到了颜色分量上,不需要再计算kCGImageAlphaPremultipliedFirst,kCGImageAlphaLast, //带alpha通道,但图片解码压缩时,并没有将alpha计算到分量,这样渲染里再计算,效率很低kCGImageAlphaFirst,kCGImageAlphaNoneSkipLast, //带alpha通道,但被忽略,相当于透明度不起作用kCGImageAlphaNoneSkipFirst,kCGImageAlphaOnly //只有alpha值,没有RGB};*/- (NSString *)alphaToString:(CGImageAlphaInfo)alpha
{switch (alpha) {case kCGImageAlphaNone:return @"kCGImageAlphaNone";break;case kCGImageAlphaPremultipliedLast:return @"kCGImageAlphaPremultipliedLast";break;case kCGImageAlphaPremultipliedFirst:return @"kCGImageAlphaPremultipliedFirst";break;case kCGImageAlphaLast:return @"kCGImageAlphaLast";break;case kCGImageAlphaFirst:return @"kCGImageAlphaFirst";break;case kCGImageAlphaNoneSkipLast:return @"kCGImageAlphaNoneSkipLast";break;case kCGImageAlphaNoneSkipFirst:return @"kCGImageAlphaNoneSkipFirst";break;case kCGImageAlphaOnly:return @"kCGImageAlphaOnly";break;default:break;}return @"UNKnow";
}- (void)lookImageInfo:(UIImage *)image
{CGImageRef imgref = image.CGImage;CGColorSpaceRef space = CGImageGetColorSpace(imgref);CGImageAlphaInfo alpha = CGImageGetAlphaInfo(imgref);CGFloat cgImageBytesPerRow = CGImageGetBytesPerRow(imgref);CGFloat cgImageHeight = CGImageGetHeight(image.CGImage);NSUInteger memorysize = cgImageHeight * cgImageBytesPerRow;//CFStringRef cs = CGColorSpaceCopyName(space);//CGColorSpaceGetName(space);NSLog(@"color space : %@, 是否alpha通道 : %@ val = %@ \n Size : %f * %f \n 内存大小 : %lu Byte \n",space,(alpha != kCGImageAlphaNone)?@"是":@"否",[self alphaToString:alpha],image.size.width,image.size.height,(unsigned long)memorysize);
}/** 缩放到指定大小(耗内存)* */
- (UIImage *)scaleImage:(UIImage *)srcImage toSzie:(CGSize)newsize
{///YES 不透明,NO透明 opaque的中文为"不透明"UIGraphicsBeginImageContextWithOptions(newsize, YES, 0);[srcImage drawInRect:CGRectMake(0, 0, newsize.width, newsize.height)];UIImage *scaleimg = UIGraphicsGetImageFromCurrentImageContext();UIGraphicsEndImageContext();return scaleimg;
}/*kCGImageSourceTypeIdentifierHint 设置一个预期的图片文件格式,需要设置为字符串类型的值kCGImageSourceShouldCache 图片解码的时候是否应该缓存,如果设置为true,在读取数据时就进行解码如果为false 则在渲染时才进行解码kCGImageSourceShouldAllowFloat 返回CGImage对象时是否允许使用浮点值 默认为kCFBooleanFalsekCGImageSourceCreateThumbnailFromImageIfAbsent 如果有缩略图则使用,无则使用原图产生缩略图kCGImageSourceCreateThumbnailFromImageAlways 用原图产生缩略图kCGImageSourceThumbnailMaxPixelSize 缩略图高或宽最大尺寸(当设置的最大值比原图的MAX(宽,高)大时,取原图的)最大取值:MIN(MAX(目标宽,目标高),MAX(原图宽,原图高))eg:原图(w=944,h=557) 目标图片大小(w=108,h=72)理论图片比例:原图 h:w = 577 /944 = 0.590042目标图 h:w = 72 / 108 = 0.6666670 < MaxPixelSize < MIN(MAX(944,557),MAX(108,,72)) = MIN(944,108) = 108;缩放后是得不到 0.666667的比例的,会按0.59的比例来,也就是最后得到的宽高会是w = 108 ,h = 108*0.59 = 63.72kCGImageSourceCreateThumbnailWithTransform 根据exif标记 自动旋转*/
/*等比例缩放 (当原图的比例和目标的比例不同时会引起图片有模糊感)@param imgdata 原图的数据@param scale 缩放倍数 0,1 时没有任何缩放,大于1时则为缩小的倍数,推荐写0这个值将会影响newsize输出的大小。如:w = 108,h = 72 (在原图和目标图1:1的情况下)scale = 3 则最后的ImageSize = (108/3,72/3)@param imgorientation 图片方向@return 返回缩放图片大小,比例和原图比例一至,不受newsize的比例影响。因此想指定到预想的宽高,这个方法只有在比例一至的情况下才能达到,否则要么高是想要的,要么宽是想要的。*/
- (UIImage *)scaleImageWithData:(NSData *)imgdata toSize:(CGSize)newsize scale:(CGFloat)scale orientation:(UIImageOrientation)imgorientation
{CGFloat maxPixelsize = MAX(newsize.width, newsize.height);CGImageSourceRef sourceref = CGImageSourceCreateWithData((__bridge CFDataRef)imgdata, nil);NSDictionary *options = @{(__bridge id)kCGImageSourceCreateThumbnailFromImageAlways:(__bridge id)kCFBooleanTrue,(__bridge id)kCGImageSourceThumbnailMaxPixelSize:[NSNumber numberWithFloat:maxPixelsize],(__bridge id)kCGImageSourceCreateThumbnailWithTransform:(__bridge id)kCFBooleanTrue,(__bridge id)kCGImageSourceCreateThumbnailFromImageIfAbsent:(__bridge id)kCFBooleanTrue};CGImageRef imgref = CGImageSourceCreateThumbnailAtIndex(sourceref, 0, (__bridge CFDictionaryRef)options);UIImage *retimg = [UIImage imageWithCGImage:imgref scale:scale orientation:imgorientation];CGImageRelease(imgref);CFRelease(sourceref);return retimg;
}///指定大小
- (UIImage *)createRGBAWithUIImage:(UIImage *)srcimage toSize:(CGSize)newsize opaque:(BOOL)opaque
{int64_t bitmapBytesPerRow = newsize.width * 4;int64_t bitmapByteCount = bitmapBytesPerRow * newsize.height;CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();if (!colorspace) {NSLog(@"create color space rgb error.");return nil;}void *bitmap = (uint32_t*)malloc(bitmapByteCount);if (!bitmap) {NSLog(@"bitmap memory alloc error.");CGColorSpaceRelease(colorspace);return nil;}CGBitmapInfo bitmapinfo = opaque? kCGImageAlphaNoneSkipLast | kCGBitmapByteOrder32Big : kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big;CGContextRef context = CGBitmapContextCreate(bitmap,newsize.width,newsize.height,8,bitmapBytesPerRow,colorspace,bitmapinfo);if (!context) {free(bitmap);NSLog(@"context create error.");CGColorSpaceRelease(colorspace);return nil;}CGRect rect = {{0,0},{newsize.width, newsize.height}};CGContextDrawImage(context, rect, srcimage.CGImage);CGImageRef imageRef = CGBitmapContextCreateImage(context);UIImage *newImage = [UIImage imageWithCGImage:imageRef];CGContextRelease(context);CGColorSpaceRelease(colorspace);return newImage;
}#pragma mark - 载剪函数- (UIImage *)CGContextClip:(UIImage *)img cornerRadius:(CGFloat)radius backgroundColor:(UIColor *)bgcolor
{int w = img.size.width;int h = img.size.height;UIGraphicsBeginImageContextWithOptions(CGSizeMake(w, h), YES, 0);CGContextRef context = UIGraphicsGetCurrentContext();///设置背景色CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor);CGContextSetBlendMode(context, kCGBlendModeNormal);CGContextFillRect(context, CGRectMake(0, 0, w, h));CGContextSaveGState(context);CGContextMoveToPoint(context, 0, radius);CGContextAddArcToPoint(context, 0, 0, radius, 0, radius);CGContextAddLineToPoint(context, w - radius, 0);CGContextAddArcToPoint(context, w, 0, w, radius, radius);CGContextAddLineToPoint(context, w, h - radius);CGContextAddArcToPoint(context, w, h, w - radius, h, radius);CGContextAddLineToPoint(context, radius, h);CGContextAddArcToPoint(context, 0, h, 0, h - radius, radius);CGContextAddLineToPoint(context, 0, radius);CGContextClosePath(context);CGContextClip(context);[img drawInRect:CGRectMake(0, 0, w, h)];CGContextDrawPath(context, kCGPathFill);CGContextRestoreGState(context);UIImage *ret = UIGraphicsGetImageFromCurrentImageContext();UIGraphicsEndImageContext();return ret;
}/*UIBezierPath 裁剪radius 相对于img的size 不要和uiimageview 的size搞混了*/
- (UIImage *)UIBezierPathClip:(UIImage *)img cornerRadius:(CGFloat)radius backgroundColor:(UIColor *)bgcolor
{int w = img.size.width;int h = img.size.height;CGRect rect = CGRectMake(0, 0, w, h);UIGraphicsBeginImageContextWithOptions(CGSizeMake(w, h), YES, 0);UIBezierPath *radiuspath =[UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:radius];if (bgcolor) {UIBezierPath *backgroundPath = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, w, h)];[bgcolor setFill];[backgroundPath fill];}[radiuspath addClip];[img drawInRect:rect];UIImage *ret = UIGraphicsGetImageFromCurrentImageContext();UIGraphicsEndImageContext();return ret;
}@end
最后是用于测试的viewcontroller
#import "testVC.h"
#import "testCell.h"@interface testVC ()<UITableViewDelegate,UITableViewDataSource>
@property (nonatomic, strong) UITableView *tabview;@end@implementation testVC- (void)viewDidLoad {[super viewDidLoad];// Do any additional setup after loading the view.self.view.backgroundColor = [UIColor whiteColor];self.tabview = [[UITableView alloc]init];self.tabview.delegate = self;self.tabview.dataSource = self;self.tabview.rowHeight = UITableViewAutomaticDimension;self.tabview.estimatedRowHeight = 100;[self.tabview registerClass:[testCell class] forCellReuseIdentifier:@"testcell"];[self.view addSubview:self.tabview];[self.tabview mas_makeConstraints:^(MASConstraintMaker *make) {make.edges.equalTo(0);}];
}- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{return 100;
}- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{testCell *cell = [tableView dequeueReusableCellWithIdentifier:@"testcell"];[cell loadDataSet:nil];return cell;
}- (void)didReceiveMemoryWarning {[super didReceiveMemoryWarning];// Dispose of any resources that can be recreated.
}@end
下面打开instrument 的core animation,来看下来回滚动时的FPS如何
主要是针对
- (void)loadDataSet:(id)dataset
{
self.lb_title.text = @"好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字";
[self.pic sd_setImageWithURL:[NSURL URLWithString:@"https://images.ihuoqiu.com/article/2018/04/07/huoqiuwang_201804072024469924.png"] placeholderImage:nil completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
UIImage *scaleimg = image;
CFTimeInterval start = CFAbsoluteTimeGetCurrent();
scaleimg = [self useWay1:image]; //方式一
// scaleimg = [self useWay2:image]; //方式二
// scaleimg = [self useWay3:image]; //方式三
CFTimeInterval end = CFAbsoluteTimeGetCurrent();
CFTimeInterval timeval = end - start;
NSLog(@"毫时 %f ms",timeval * 1000);
dispatch_async(dispatch_get_main_queue(), ^{
self.pic.image = scaleimg;
});
[self lookImageInfo:scaleimg];
});
}];
}
这部分代码进行分晰,全程真机
情况一: 注释这个,即回到没有优化过的状态(存在blended layers,和misaligned images的问题)。只有一个lable和一个SD异步下载图片
///clean blended layers
// [self settingLabelCleanBlended];
// [self settingAvatar];
///使用光栅
// [self settingeRasterize];
- (void)loadDataSet:(id)dataset
{
self.lb_title.text = @"好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字";
[self.pic sd_setImageWithURL:[NSURL URLWithString:@"https://images.ihuoqiu.com/article/2018/04/07/huoqiuwang_201804072024469924.png"] placeholderImage:nil completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
self.pic.image = image;
}];
}
再来看下只是把圆角开启有多少影响
///圆角
- (void)settingAvatarRadius
{
self.avatar.layer.cornerRadius = 22;
self.avatar.layer.masksToBounds = YES;
}
经过多次试验,在少量的图片存在圆角时影响不是很大也就3 FPS 之间的差距左右(大家可以下代码亲自跑)
再来看下把这个优化后是不是有很大的性能提升?
///clean blended layers
[self settingLabelCleanBlended];
[self settingAvatar];
//使用光栅
[self settingeRasterize];
// [self settingAvatarRadius];
- (void)loadDataSet:(id)dataset
{
self.lb_title.text = @"好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字好多字";
[self.pic sd_setImageWithURL:[NSURL URLWithString:@"https://images.ihuoqiu.com/article/2018/04/07/huoqiuwang_201804072024469924.png"] placeholderImage:nil completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
UIImage *scaleimg = image;
CFTimeInterval start = CFAbsoluteTimeGetCurrent();
scaleimg = [self useWay1:image]; //方式一
// scaleimg = [self useWay2:image]; //方式二
// scaleimg = [self useWay3:image]; //方式三
CFTimeInterval end = CFAbsoluteTimeGetCurrent();
CFTimeInterval timeval = end - start;
NSLog(@"毫时 %f ms",timeval * 1000);
dispatch_async(dispatch_get_main_queue(), ^{
self.pic.image = scaleimg;
});
[self lookImageInfo:scaleimg];
});
}];
}
通过观察,优化后60FPS的占比的确高了不少。
因此在解决卡顿时,根据页面的复杂度,优先处理耗时问题,可以用time profiler来进行检测,再来考虑优化blended layers,misaligned,off-screen render。
转载请注明出处。
性能优化之FPS实践报告。相关推荐
- 关于性能优化的一些实践
关于性能优化的一些实践 2 背景 在海量并发业务的场景下,比如电商抢购.微信红包这样的场景下,我们经常会遇到各种各样的性能问题,在应对这些问题的时候,应该有怎样的方法论去指导我们解决问题,基于这几年的 ...
- Flutter Web 在《一起漫部》的性能优化探索与实践
一起漫部 是基于区块链技术创造的新型数字生活. 目录 前言 开发环境 渲染模式 首屏白屏 优化方案 启屏页优化 包体积优化 去除无用的icon 裁剪字体文件 deferred延迟加载 启用gzip压缩 ...
- 让数据中台飞起来—— Quick BI性能优化解决方案及实践
Quick BI"数据门户"在企业数据中台建设中的重要性 企业在数据中台初步建设完成以后,怎样让客户直观感受到数据中台的价值?企业决策者.各部门管理人员.业务运营人员如何通过统一的 ...
- Java 性能优化实战工具实践:如何获取代码性能数据?
首先解答一下上一课时的问题.磁盘的速度这么慢,为什么 Kafka 操作磁盘,吞吐量还能那么高? 这是因为,磁盘之所以慢,主要就是慢在寻道的操作上面.Kafka 官方测试表明,这个寻道时间长达 10ms ...
- FlutterWeb性能优化探索与实践
点击"开发者技术前线",选择"星标" 让一部分开发者看到未来 来自:美团技术团队 美团外卖商家端基于 FlutterWeb 的技术探索已久,目前在多个业务中落地 ...
- 让数据中台“飞“起来— Quick BI性能优化解决方案及实践
1 引言 Quick BI"数据门户"在企业数据中台建设中的重要性 企业在数据中台初步建设完成以后,怎样让客户直观感受到数据中台的价值?企业决策者.各部门管理人员.业务运营人员如何 ...
- 京东微信购物性能优化,最佳实践总结!
京东微信购物首页(以下简称微信首页)曾经作为微信购物一级入口(目前替换为京喜小程序)一直对性能有着极高的要求,本文将介绍微信首页的一些优化经验. 一般来说产品是按以下方式进行迭代的,我认为循环的起点应 ...
- 一文了解 NextJS 并对性能优化做出最佳实践
点击上方 前端Q,关注公众号 回复加群,加入前端Q技术交流群 引言- 从本文中,我将从是什么,为什么,怎么做来为大家阐述 NextJS 以及如何优化 NextJS 应用体验. 一.NextJS是什么- ...
- 谷歌浏览器LightHouse性能优化分析神器实践运用
1 基本操作介绍 1.1 入口 打开最新版本Google Chrome,F12一下弹出开发者页面,在顶部的导航栏选项选择Lighthouse选项(旧版本的浏览器是需要从应用商店下载Lighthouse ...
最新文章
- Java-Web JSP指令、javabean和EL表达式
- 刷题总结——烽火传递(单调队列+dp)
- 1.QT中的容器QVector,QList,QSet,QMap,QQueue,QStack,QMultiMap,QSingleList等
- 【HarmonyOS】开发工具【DevEco Studio】下载安装
- ios把数据传递到另一个页面_iOS 委托 页面之间传递数值
- javax.servlet.ServletException: Circular view path []: would dispatch back to the current....
- 用国产还是国外?BI工具深度盘点洞察,选这个肯定没差
- 设计模式09_代理模式
- 把一个数组的值赋给另一个数组(VB.NET)
- UCOSII学习笔记[开篇]
- struts2中,在使用 convention 插件的情况下,如何使用 “chain” 这个resu
- adb shell 出现 error :
- 牛客暑期多校第五场A:gpa题解(简单01分数规划)
- 行政区划分与省直辖县级市
- 黑鲨官网装机大师工具如何重装win10系统,win10系统重装
- Android WMS架构:WindowContainer树形组合模式-理论基础+实践结果
- mysql_帮助命令/通配搜索/help help用法(official doc)
- 电信光猫F660 4台限制破解
- 水星路由器wan口ip显示0_wan口状态ip地址为0.0.0.0
- 哔哩哔哩,除了二次元的其他东西,包爽