短视频app源码,借助轮询优化交互体验

news/2025/1/15 15:40:05/文章来源:https://www.cnblogs.com/yunbaomengnan/p/18401314

业务背景

在短视频app源码前后端数据交互场景下,使用最多的一种方式是客户端发起 HTTP 请求,等待服务端处理完成后响应给客户端结果。
但在一些场景下,短视频app源码服务端对数据的处理需要较长的时间,比如提交一批数据,对这批数据进行数据分析,将最终分析结果返回给前端。
如果采用一次 HTTP 请求,用户会一直处于等待状态,再加上界面不会有进度交互,导致用户不知何时会处理完成;此外,一旦刷新页面或者其他意外情况,用户就无从感知处理结果。
面对这类场景,可以借助 「HTTP 轮询方式」 对交互体验进行优化,具体过程如下:
首先发起一次 HTTP 请求用于提交数据,之后启动轮询在一定间隔时间内查询分析结果,在这期间后台可将分析进度同步到前端来告知用户处理进度;此外即使刷新再次进入页面还可以通过「轮询」实时查询进度结果。
下面,我们来看看代码层面看如何实现这类场景。

JS 实现轮询的方式

在实现代码之前,我们需要先明确 JS 实现轮询的方式有哪些,哪种方式最适合使用。

1. setInterval

作为前端开发人员,提起轮询第一时间能想到的是计时器 setInterval,它会按照指定的时间间隔不间断的轮询执行处理函数。

let index = 1;setInterval(() => {console.log('轮询执行: ', index ++);
}, 1000);

 

回过头来看我们的场景:要轮询的是 异步请求(HTTP),请求响应结果会受限制网络或者短视频app源码的服务器处理速度,显然 setInterval 这种固定间隔轮询并不适合这个场景。

2. Promise + setTimeout sleep

setInterval 的不足之处在于 轮询间隔时间 在异步请求场景下无法保证两个请求之间的间隔固定。要解决这个问题,可以使用 sleep 睡眠函数来控制间隔时间。
JS 中没有提供 sleep 相关方法,但可以结合 Promise + setTimeout 来实现。

const sleep = () => {return new Promise(resolve => {setTimeout(resolve, 1000);});
}

 

sleep 仅控制了轮询间隔,而轮询的执行机制需要我们手动根据异步请求结果来实现,比如下面通过控制 while 循环的条件:

const start = async () => {let i = 0;while (i < 5) {await sleep();console.log(`第 ${++ i} 次执行`);}
}start();

 

使用轮询的时候可以借助 async/await 同步的方式编写,提高代码阅读质量。

实现异步请求轮询

下面我们通过一个完整示例理解 轮询异步请求 的实现及使用注意事项。
首先我们定义两个变量:index 用于控制何时停止轮询,timer 则用于实现中断轮询。

let index = 1;
let timer = 0;

 

这里,我们定义 syncPromise 来模拟异步请求,可以看作是一次 HTTP 请求,当进行 5 次异步请求后,会返回 false 表示拿到数据分析结果,停止数据查询轮询:

const syncPromise = () => {return new Promise(resolve => {setTimeout(() => {console.log(`第 ${index} 次请求`);resolve(index < 5 ? true : false);index ++;}, 50);})
}

 

现在,我们实现 pollingPromise 作为 sleep 睡眠函数使用,去控制轮询的间隔时间,并在指定时间执行异步请求:

const pollingPromise = () => {return new Promise(resolve => {timer = setTimeout(async () => {const result = await syncPromise();resolve(result);}, 1000);});
}

 

最后,startPolling 作为开始轮询的入口,包含以下逻辑:

1)在轮询前会清除正在进行的轮询任务,避免出现多次轮询;
2)如果需要,在开始轮询时会立刻调用异步请求查询一次数据结果;
3)最后,通过 while 循环根据异步请求的结果,决定是否继续轮询;

const startPolling = async () => {// 清除进行中的轮询,重新开启计时轮询clearTimeout(timer); // !!! 注意:清除计时器后,会导致整个 async/await 链路中断,若计时器的位置下方还存在代码,将不会执行。index = 1;// 立刻执行一次异步请求let needPolling = await syncPromise();// 根据异步请求结果,判断是否需要开启计时轮询while (needPolling) {needPolling = await pollingPromise();}console.log('轮询请求处理完成!'); // 若异步请求被 clearTimeout(timer),这里不会被执行打印输出。
}const start = async () => {await startPolling();console.log('若异步请求被 clearTimeout(timer),这里将不会被执行');
}
start();

 

不过,需要注意的是:一旦清除计时器后,会导致整个 async/await 链路中断,若计时器的位置下方还存在代码,将不会执行。
假设当前执行了两次轮询被 clearTimeout(timer) 后,从 startPolling 到 start 整个 async/await 链路都会中断,且后面未执行的代码也不会被执行。
基于以上规则,异步轮询的处理逻辑尽量放在 syncPromise 异步请求核心函数中完成,避免在开启轮询的辅助函数中去实现。

使用轮询的其他场景

在短视频app源码中,使用轮询的场景还有很多。
通常我们考虑首屏加载速度,会将一些非主要启动程序的资源改用 动态异步 的方式去加载。
如果某个页面渲染时依赖了异步加载的脚本资源,就会出现无法拿到资源变量导致报错情况,因为这个时候其实资源还没有加载完成。
所以就需要一种手段,在资源加载完成后再让页面拿去使用,轮询脚本资源变量是否存在可以作为一种处理方式。

/*** 轮询查询异步资源的加载状态*/
export const pollingAsyncResource = (handler: Function, condition: () => unknown) => {let timer = 0;if (!!condition()) {// 静态资源已加载完成
    handler();} else {// 启动轮询查询静态资源加载状态timer = window.setInterval(() => {if (condition()) {// 静态资源已加载完成
        clearInterval(timer);handler();}}, 50);}
}// 使用
pollingAsyncResource(() => // 使用资源的具体逻辑, () => window.$
);

 

在 pollingAsyncResource 中启动 计时器轮询 去查询静态资源是否加载完成。
参数 handler 是资源加载完成后要执行的具体逻辑;condition 则是判断资源是否加载完成的条件,一般脚本资源都采用 umd 模块形式在 window 对象上绑定全局变量。

以上就是短视频app源码,借助轮询优化交互体验, 更多内容欢迎关注之后的文章

 

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

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

相关文章

常用delphi IDE环境配置

目录 常用delphi XE IDE环境配置,大家都需要熟练 一、android SDK : 二、环境变量 User System Overrides :覆盖用户操作系统的全局配置参数:System Variables 操作系统层面的全局变量: 其中:重要的,和自己个性化的: 三、自己的类库路径 四、测试工程默认路径 五、…

如果没有热风枪,如何组合热缩管的5种简单方法

转载自:https://mil.sohu.com/a/779354413_120429259当谈到收缩热缩管时,没有什么比热风枪更好的了。但如果你没有,你该怎么办? 请放心,您仍然可以在没有热风枪的情况下使用热缩管。它可以响应多种热源,因此您可以使用许多替代工具。 在本文中,我列出了一些最流行的热收…

17_电话号码的字母组合

17_电话号码的字母组合 【问题描述】 给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按任意顺序返回。给出数字到字母的映射如下(与电话按键相同)。注意1不对应任何字母。示例一: 输入:digits = "23" 输出:["ad","ae&q…

读软件设计的要素03概念的组合

概念的组合1. 概念的组合 1.1. 概念不像程序那样,可以用较大的包含较小的1.1.1. 每个概念对用户来说都是平等的,软件或系统就是一组串联运行的概念组合1.2. 概念是通过操作来同步组合的1.2.1. 同步并不增加新的概念操作,但会限制已有的操作,从而消除一些独立概念可能会出现…

南沙信C++陈老师解一本通题: 1101:不定方程求解

​ 【题目描述】给定正整数a,b,c。求不定方程 ax+by=c关于未知数x和y的所有非负整数解组数。【输入】一行,包含三个正整数a,b,c 两个整数之间用单个空格隔开。每个数均不大于1000。【输出】一个整数,即不定方程的非负整数解组数。【输入样例】 2 3 18 【输出样例】 4 #in…

musl libc 与 glibc 在 .NET 应用程序中的兼容性

musl Linux 和 glibc 是两种不同的 C 标准库实现,它们在多个方面存在显著差异。历史和使用情况:glibc 是较早且广泛使用的 C 标准库实现,具有较长的开发历史和广泛的社区支持。它被大多数 Linux 发行版采用,特别是在桌面和服务器环境中。 musl 是一个相对较新的实现,旨在提…

JDBC,SQL注入,事务,C3P0于Druid连接池(最详细解析)

JDBCJDBC(Java DataBase Connectivty,Java数据库连接)API,是一种用于执行Sql语句的Java API,可以为关系型数据库提供统一的访问,其由一组Java编写的类和接口组成.JDBC驱动程序起初,SUN公司推出JDBC API希望能适用于所有数据库,但实际中是不可能实现的,各个厂商提供的数据库差异…

Redis 入门 - 安装最全讲解(Windows、Linux、Docker)

最全的Redis安装教程,本文介绍了Redis在Windows(官方建议、脚本、可执行文件方式)、Linux(apt包管理器、源码编译)及Docker下的安装过程,详细步骤包括命令执行、文件操作等。经过上一章节的介绍,相信大家对Redis已经有了大致的认知,今天主要给大家详细讲解Redis在Windo…

WPF在UserControl使用MVVM模式实现窗体移动,最大化,最小化,关闭

1、在WPF中,我们移动窗体,可以使用MouseDown或者MouseLeftButtonDown去触发DragMove方法 2、当我们使用UserControl的时候,它是没有DragMove方法的,这个时候怎么办 我们改为命令的形式,可以直接调出当前的窗体,或者将窗体当参数传入到ViewModel,也没问题 我写了 <i:I…

ATTCK红队评估(红日靶场2)CS篇

靶机介绍红队实战系列,主要以真实企业环境为实例搭建一系列靶场,通过练习、视频教程、博客三位一体学习。本次红队环境主要Access Token利用、WMI利用、域漏洞利用SMB relay,EWS relay,PTT(PTC),MS14-068,GPP,SPN利用、黄金票据/白银票据/Sid History/MOF等攻防技术。关…

esp32笔记[18]-使用汇编在riscv架构的esp32c3点灯

使用esp-idf工具链编译汇编程序实现在riscv架构的esp32c3点灯. Compiling an assembly program using the esp-idf toolchain to blink an LED on the RISC-V based ESP32-C3.摘要 使用esp-idf工具链编译汇编程序实现在riscv架构的esp32c3点灯. Abstract Compiling an assembly…