近期,我们对腾讯课堂小程序做了一次全方位的性能优化,本篇文章将从网络请求的角度分享一种优化的思路。我们引入了一种请求排队的策略,通过控制不同优先级请求的发送顺序,保障影响页面渲染的关键请求能够及时发送,并迅速得到返回结果。由请求测速数据统计,我们的关键请求耗时实现了 50-100 ms,约 15% 的优化。
某个平淡无奇的工作日,我们的小程序在 iOS 上突然无比的卡顿。
紧急排查之后,发现我们使用的一个第三方上报服务异常,导致我们的上报请求一直处于 pending 状态。
这时,小程序官方文档的网络使用说明映入眼帘:
wx.request、wx.uploadFile、wx.downloadFile 的最大并发限制是 10 个。
也就是说,由于并发限制,当处于 pending 状态的请求数达到 10 个时,后续调用 wx.request 发送的请求可能会被阻塞。
时间较为久远,没有留下证物,我们通过模拟请求超时来还原一下当时的现场。
借助 whistle 的 resDelay 方法,可以将 report 和 log 两种上报请求延迟 5000ms 返回:
可以看到由于上报请求一直处于 pending 状态,导致后续发送的业务请求 get_homepage_feeds_h5 也一直在 pending 中,页面加载变得卡顿起来。
排查到问题后,我们紧急下掉了异常请求,现网突发的卡顿问题得以解决。
但是,这次的异常引起了大家的注意:上报请求竟然会对业务请求造成如此大的影响。我们似乎应该通过一些方式,保障与用户体验相关的业务请求正常发送。
网络请求的耗时与许多因素相关,用户的网络环境以及提供接口的服务质量,我们无法在前端控制。
但如果我们可以给小程序的网络请求设置优先级,当多个请求并发时,让低优先级的上报请求给高优先级的业务请求让路,是否也能让业务请求速度提升,优化用户体验呢?
我们设计的请求优先策略如下:
1 . 将请求分为高优先与低优先两种等级。
2 . 当并发请求数超过一定阈值时,仅发送高优先级请求,拦截低优先级请求的发送。
3 . 并发请求数量下降后,补发被拦截的低优先级请求。
4 . 设置最长等待时间,超时后主动发送低优先请求,避免过度延时。
小程序的 HTTPS 请求是通过 wx.request API 发送的,我们可以通过拦截这个 API 来实现对所有请求的发送顺序控制。整块逻辑我们封装到一个 排队请求模块 来实现,模块中提供一个与 wx.request 具有相同函数签名的方法,用来替换原始的请求 API。
threshold: 并发请求数的阈值。当正在进行的请求数超过这个阈值时,延迟发送低优先请求。
maxWaitingTime: 最长等待时间。等待队列中的请求等待超过该时间后,主动补发,避免过度延时。
lowPriority: 一组匹配方式(正则等)。用于判断请求是否属于低优先级。
目前我们设置 threshold 为 5,主要出于以下两方面考虑:
1 . 给后续可能到来的业务请求预留 5 个坑位,避免阻塞。
2 . 已有 5 个请求并发时,延迟上报请求发送,也可减少并发造成的网络争抢。
模块基本功能由 3 个类实现:
加入等待队列:正在进行的请求数超过设置的 threshold ,且请求为低优先级时;
加入请求池:请求为高优先级,或并发数未达到 threshold 。
2 . 等待队列 WaitingQueue :维护需要延时发送的请求等待队列。在请求池空闲或请求超过最长等待时间时,补发等待请求。
3 . 请求池 RequestPool :发送请求并维护所有正在进行的请求的状态。对外暴露正在进行的请求数量,并在有请求完成时通知等待队列尝试补发。
这里简单通过各个类的接口来描述一下类之间的包含、调用关系:
QueueRequest 类
class QueueRequest {
// 请求池
private requestPool: RequestPool;
// 等待队列
private waitingQueue: WaitingQueue;
// 用于替代wx.request的请求方法
request(opts: WechatMiniprogram.RequestOption): WechatMiniprogram.RequestTask;
}
WaitingQueue 类
class WaitingQueue {
// 等待发送的请求队列
private queue: QueueRequestOption[];
// 检查队列是否有超过最大等待时长的请求
private checkQueue();
// 将一个参数为opt的新请求加入等待队列
public enqueue(opts: QueueRequestOption);
// 发送等待队列的第一个的请求
public dequeue();
// 获取等待队列的长度
public getWaitingNum():number;
}
RequestPool 类
interface RequestPoolConfig {
onReqComplete?: () => void;
}
class RequestPool {
// 真实的wx.request方法
private originRequest = wx.request.bind(wx);
// 请求池,记录正在进行中的请求
private pool;
// 将一个参数为opts的请求加入请求池并发送
public add(opts: QueueRequestOption);
// 请求完成时,将标识为seq的请求移出请求池,并触发onReqComplete事件
private remove(seq: number);
// 获取请求池内请求数量
public getReqNum():number;
}
QueueRequest中维护了 WaitingQueue 和 RequestPool 两个类的实例。
通过 WaitingQueue.enqueue() 将请求加入等待队列;
通过 ReuqestPool.add() 将请求放入请求池,直接发送;
QueueRequest.request()方法用于替代 wx.request,在实际调用 wx.request 前执行请求分发逻辑。
此时,我们已经可以通过 QueueRequest.request() 方法,控制不同优先级请求的发送顺序了。
然而,根据 API 文档,调用 wx.request 会返回一个 RequestTask 对象。那么进入等待队列的请求,在没有调用 wx.request 时,要如何同步地返回该对象呢?
我们设计了 RequestTaskProxy 类来模拟真实的 RequestTask。
增加了 RequestTaskProxy 后,新的请求进入排队请求模块,形成了如下的调用链路:
RequestTaskProxy 类的大致实现如下:
export class RequestTaskProxy implements WechatMiniprogram.RequestTask {
// 真实的RequestTask
private task?: WechatMiniprogram.RequestTask;
// 未绑定真实RequestTask时的操作记录
private operations: [];
/**
* 设置真正发起请求后返回的requestTask
* @param requestTask 实际wx.request返回对requestTask
*/
public setRequestTask(requestTask: WechatMiniprogram.RequestTask) {
this.task = requestTask;
this.operations.forEach((op) => {
// 将this.operations重放到requestTask上
// ...
});
this.operations = [];
}
// 模拟RequestTask的接口
public abort() {
if (this.task) {
this.task.abort();
} else {
this.operations.push({ type: 'abort' });
}
}
// 模拟RequestTask的接口
public offHeadersReceived(callback?: WechatMiniprogram.OffHeadersReceivedCallback) {
if (this.task) {
this.task.offHeadersReceived(callback);
} else {
this.operations.push({ type: 'off', cb: callback });
}
}
// 模拟RequestTask的接口
public onHeadersReceived(callback: WechatMiniprogram.OnHeadersReceivedCallback) {
// 类似offHeadersReceived
// ...
}
}
由于 wx.request 属性的 writable 被设置为 false,不能直接赋值,我们只能通过 Object.defineProperty 替换该属性的 value 值。
class QueueRequest {
request(opts: WechatMiniprogram.RequestOption): RequestTask;
// 替换wx.request方法
make() {
Object.defineProperty(wx, 'request', { value: this.request.bind(this) });
}
}
/**
* 对外暴露的方法,调用后注入排队请求逻辑
* @param config 配置项
*/
export function useRequestQueue(config: QueueRequestConfig) {
const queueRequest = new QueueRequest(config);
queueRequest.make();
return queueRequest;
}
在小程序中,调用 useRequestQueue() 方法,即可拦截 wx.request API,按照配置的优先级控制请求顺序了。
在后台服务没有任何改动的情况下,我们在前端干预了部分用户网络请求的顺序,并上报统计了从发起业务请求到获得请求结果的耗时。
该耗时的计算近似于请求 API 触发 complete 回调的时间 - 调用注入后的 wx.request 的时间。
我们随机选择了一批用户进行灰度,经过一段时间后,得到了对比数据:
注:图表的纵轴为用户 业务请求(高优先) 的平均耗时,横轴为时间轴
绿色曲线来自不做干预的普通用户
黄色曲线来自应用请求优先策略的灰度用户
从图中可以看到,对网络请求顺序的干预效果明显,灰度用户业务请求耗时平均有 50-100ms,约 15% 的优化。
注:图表的纵轴为用户 业务请求(高优先) 耗时,横轴为时间轴
曲线大致可分为三组,每组两条曲线,选取不同百分位的请求耗时对比,从上到下依次为:
我们发现:对网络请求顺序的干预在耗时长的网络请求中效果更为明显。也就是说,这次的优化效果主要作用在弱网用户上。
该表现是符合预期的,因为在弱网环境下,更容易发生请求堆积,对业务请求造成阻塞。
本文由哈喽比特于3年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/g2mLpWhGsrMEud-i8xD6YQ
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。