视频上传 - 断点续传那点事

在上一篇文章中,我们讲解了分片上传的实现方式。在讲解断点续传之前,我要把上篇文章中留下的问题讲解一下。读过上一篇文章的小伙伴们都知道,对于分片上传来说,它的传输方式分为2种,一种是按顺序传输,一种是并发的方式传输

上一篇里,我们只讲解了第一种方式,第二种方式并没有过多的去讲解。接下来,小编会带着大家,一步步拆解这个内容。大家系好安全带,面试题要来了。

如何实现分片的并发上传?

大家肯定都刷到过这样的面试题:给你100张图片,如何实现并发上传
首先我们要知道,浏览器一次性能发送多少个请求?答案是6个。那也就是说,我们需要设计一个流程,每次并发6个,直到所有的请求都完成响应。
那如何实现并发呢?

Promise似乎提供了一些方法,比如 Promise.allSettledPromise.allPromise.race

那这个时候,面试题又来了,它三的区别是什么在这个场景里,使用哪个API更合理?

共同点:参数都是由Promise实例组成的数组。

不同点:返回值不同。Promise.allSettled返回的是所有实例的状态数组。all与race返回的都是对象,最先成功或者失败的对象。

在我们这个场景里,我们优先选择 Promise.allSettled。知道了并发的方式还远远不够,假设我们有10个地址,一次并发发送6个请求,所以需要2次并发6个请求。那这个2次该如何得知呢?最简单也最实用的方案就是通过 Array.splice方法 来切割数组。因为splice进行删除操作时会影响到原数组,也就是原数组里也没有了被删除的元素。那我们就可以通过while循环来判断原数组是否还有剩余元素。没有剩余元素意味着并发请求结束了。

这个时候一个知识点也过来了。一起复习一下,slice与splice有什么区别?

  • 作用不一样。slice只能用来删除元素。splice可通过参数来决定删除或者添加元素的操作。
  • 对原数组的影响不一样。slice不会影响原数组。无论splice进行的是删除操作 还是 添加操作,它都会影响到原数组。

讲了这么多理论,也是时候动手实践一波了:

let arr = [{name: 1},{name: 2},{name: 3},{name: 4},{name: 5},{name: 6},{name: 7},{name: 8},{name: 9},{name: 10},{name: 11},
];async function ax(){while(arr.length > 0){let newArr = arr.splice(0, 6);let result = await Promise.allSettled(newArr.map(item => {return new Promise((resolve, reject) => {setTimeout(() => {return resolve(item.name)},1000)})}));console.log('result是撒谎:', result);}
}ax();

执行一下上述代码,我们会发现,按照了我们的预期,过了1s,控制台同时打印了1-6。再过了1s,控制台同时的打印了剩余元素。

那我们把这个思想转换到 分片上传的代码里。

// Video组件里的其他内容均不变,有不清晰的请看前2篇文章 ==========// 并发分片上传
concurrencyUploadChunkFile = async () => {let self = this;// 定义每块体积大小为5MBlet chunk_size = 5 * 1024 * 1024;// 当前上传的文件对象let fileObj = this.state.fileObj;// 当前上传的文件对象的体积let allSize = this.state.fileObj.size;// 当前文件被切割的总分片数量let allChunkCount = Math.ceil(allSize / chunk_size);// chunk文件集合let chunkArr = [];for (let index = 0; index < allChunkCount; index++){let startIndex = index * chunk_size;let endIndex = Math.min(startIndex + chunk_size, allSize);chunkArr.push({data: fileObj.slice(index * chunk_size,endIndex),filename: `chunk-${index}`,chunkIndex: index});}// 开始并发分片上传while(chunkArr.length > 0){let reqArr = chunkArr.splice(0, 6);let reqArrFactory = reqArr.map(item => {return new Promise((resolve, reject) => {let result = this.uploadChunkReq(item.data, item.chunkIndex, 'chunk');return resolve(result);})})let resArr = await Promise.allSettled(reqArrFactory);console.log('6个请求的响应如何:', resArr);}// 合并请求// this.mergeChunk();render(){return <div><button onClick={this.concurrencyUploadChunkFile}>并发上传</button></div>}}

在上述代码中,我们定义了分片的体积为5M,此时假如我们分片上传了一个61M的视频,根据计算,会得到13个分片,如果我们控制网速,能明显的看到分层才对。因为毕竟发了3波,每波都是发送6个请求,每波之间都是按顺序的。就像下面这样:

在这里插入图片描述
并发上传分片到这里就结束啦。但如果想扩展的话,其实还有很多考题,就拿并发来举例子,大家可能还会听到一些考题,比如实现并发的方法有哪些?Promise.allSetlled是如何实现的等等。

我想说的是,大家不要去刻意背这些东西,因为这些题的本质就一个,就是js异步对象的运行机制。当你深入理解了就会发现,真的是举一反三。

断点续传

直到目前为止,大家有没有发现,我们进展的过于顺利,如果在上传分片的过程中出现了失误,我们应该怎么办?

断点续传是一个防错机制。它在大文件上传失败时,不必重新来过,从断掉的地方重新上传即可。

如何实现呢?很简单,从哪个分片断掉,就从哪块上传呗。

但是大家也会发现,即使是最简单的场景,根据每个项目实现分片上传的方式不同,断点续传的方法也不尽一样。因为断点续传的方式不一样,所以导致后端实现合并分片的方式也会随之改变。举个例子:

假如,我们有13个分片,序号分为是1-13,先并发1-6,此时我们发现分片6失败了,然后我们维护一个失败分片的数组,将分片6 push进去。接着并发 7 -12,此时都成功了。最后发送13,也成功了。因为分片6失败了,所以我们还需要再发送分片6,最后发现分片6也成功了。但是对于后端来说,在合并分片的时候就需要新增排序逻辑了,因为分片的序号对不上了。大家懂我的意思吧。

这里我们来新增前端处理断点续传的逻辑。逻辑如下:

  • 定义一个失败的分片集合
  • while循环时,通过判断原分片数组的长度是否为0,来确定所有的分片是否都上传了。
  • 在上传的过程中,如果有分片失败的,就将它push到 失败分片集合里。
  • 当原分片集合为空时,意味着此时应该重传失败的分片了。

// 其他内容不变 =======// 并发上传分片
concurrencyUploadChunkFile = async () => {let self = this;// 定义每块体积大小为5MBlet chunk_size = 5 * 1024 * 1024;// 当前上传的文件对象let fileObj = this.state.fileObj;// 当前上传的文件对象的体积let allSize = this.state.fileObj.size;let allChunkCount = Math.ceil(allSize / chunk_size);// 失败的分片集合(新增++++++++++++++++++++++++++++)let failedChunkArr = [];// chunk文件集合let chunkArr = [];for (let index = 0; index < allChunkCount; index++){let startIndex = index * chunk_size;let endIndex = Math.min(startIndex + chunk_size, allSize);chunkArr.push({data: fileObj.slice(index * chunk_size,endIndex),filename: `chunk-${index}`,chunkIndex: index});}// 开始分片上传(update++++++++++++++++++++++++++++++++++++++++)while(chunkArr.length > 0 || failedChunkArr.length > 0){let reqArr = chunkArr.length > 0 ? chunkArr.splice(0, 6) : failedChunkArr.splice(0, 6);let reqArrFactory = reqArr.map(item => {return new Promise((resolve, reject) => {let result = this.uploadChunkReq(item.data, item.chunkIndex, 'chunk');if (result?.code != 200){failedChunkArr.push(item);}return resolve(result);})})let resArr = await Promise.allSettled(reqArrFactory);console.log('6个请求的响应如何:', resArr);}// 合并请求// this.mergeChunk();}

最后

好啦,本篇文章到这里就结束啦,如果上述过程中有明显的错误,欢迎大家指正,希望我讲的对大家有帮助,那么我们下期再见啦,拜拜~~

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

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

相关文章

高亮显示不一致

先准备好测试文件 [rootnode4 ~]# cat 2.1 No. Table Name Src Count Des Count Result 1 sbtest1 100 100 PASS 2 sbtest2 200 300 NOTPASS 3 sbtest3 150 150 …

Go语言每日一练 ——链表篇(三)

传送门 牛客面试笔试必刷101题 ---------------- 链表中的节点每k个一组翻转 题目以及解析 题目 解题代码及解析 package main import _"fmt" import . "nc_tools" /** type ListNode struct{* Val int* Next *ListNode* }*//*** 代码中的类名、方…

STM32 硬件随机数发生器(RNG)

STM32 硬件随机数发生器 文章目录 STM32 硬件随机数发生器前言第1章 随机数发生器简介1.1 RNG主要特性1.2.RNG应用 第2章 RNG原理框图第3章 RNG相关寄存器3.1 RNG 控制寄存器 (RNG_CR)3.2 RNG 状态寄存器 (RNG_SR)3.3 RNG 数据寄存器 (RNG_DR) 第3章 RNG代码部分第4章 STM32F1 …

三月济南举办2024第八届生物饲料高质量发展论坛

饲料工业发展空间大&#xff0c;产量持续增长&#xff0c;品质与质量也在不断提高&#xff0c;饲料工业是支撑现代畜牧水产养殖业发展的基础产业&#xff0c;是关系到城乡居民动物性食品供应的民生产业。“十四五”时期是我国由全面建设小康社会向基本实现社会主义现代化迈进的…

Xampp中Xdebug的安装使用

工欲善其事&#xff0c;必先利其器 XDebug简介 XDebug 是一个用于 PHP 的调试和性能分析工具。它提供了一系列功能&#xff0c;帮助开发者在开发和调试 PHP 应用程序时更加高效。 以下是 XDebug 的一些主要特性和功能&#xff1a; 调试功能&#xff1a; 断点调试&#xff1a;…

CSS的动画

CSS的动画 在本节&#xff0c;我们将学习keyframes动画。 1. 动画的基本使用 1. 定义动画 定义动画有两种写法&#xff1a; 简单定义方式 keyframes 动画名 {/* from代表初始状态 */from {/*property1:value1*/transform: translate(0%);}/* to代表结束状态 */to {transfor…

海外社媒运营必学:优化Instagram SEO的必学策略

Instagram SEO 是优化 Instagram 内容以使其在平台搜索结果中被发现的做法。如果你希望你可以更快的让你的Ins获得流量&#xff0c;做好SEO就成功了一半。Instagram 搜索结果包括相关内容、帐户、音频、主题标签和地点&#xff0c;下面为你总结10个策略技巧&#xff01; 一、In…

Go语言每日一练链表篇(二)

传送门 牛客面试笔试必刷101题 ---------------- 链表内指定区间反转 题目以及解析 题目 解题代码及解析 package main import _"fmt" import . "nc_tools" /** type ListNode struct{* Val int* Next *ListNode* }*//*** 代码中的类名、方法名、参…

【Leetcode】2641. 二叉树的堂兄弟节点 II

文章目录 题目思路代码结果 题目 题目链接 给你一棵二叉树的根 root &#xff0c;请你将每个节点的值替换成该节点的所有 堂兄弟节点值的和 。 如果两个节点在树中有相同的深度且它们的父节点不同&#xff0c;那么它们互为 堂兄弟 。 请你返回修改值之后&#xff0c;树的根 …

Node.js版本管理工具之_Volta

Node.js包管理工具之_Volta 文章目录 Node.js包管理工具之_Volta1. 官网1. 官网介绍2. 特点1. 快( Fast)2. 可靠(Reliable)3. 普遍( Universal) 2. 下载与安装1. 下载2. 安装3. 查看 3. 使用1. 查看已安装的工具包2. 安装指定的node版本3.切换项目中使用的版本 1. 官网 1. 官网…

利用LLM大模型生成sql的深入应用探究

Chat2DB 是一款有开源免费的多数据库客户端工具,和传统的数据库客户端软件Navicat、DBeaver 相比 Chat2DB 集成了 AIGC 的能力&#xff0c;能够将自然语言转换为 SQL&#xff0c;也可以将 SQL 转换为自然语言&#xff0c;可以给出研发人员 SQL 的优化建议&#xff0c;极大地提升…

【C语言】GtkStack及标签页的关闭

一、GtkStack GtkStack 是 GTK&#xff08;GIMP Toolkit&#xff09;库中的一个容器类&#xff0c;用于管理多个子窗口部件&#xff08;widgets&#xff09;&#xff0c;但在任何给定时间内只显示其中一个。GtkStack 提供了一种在同一个空间位置显示不同内容的方式&#xff0c…

npm修改镜像源

背景&#xff1a;切换npm镜像源是经常遇到的事&#xff0c;下面记录下具体操作命令 1. 打开终端运行"npm config get registry"命令来查看当前配置的镜像源 npm config get registry2. 修改成淘宝镜像源"https://registry.npmjs.org/" npm config set re…

前端工程化之:webpack2-2(内置插件)

目录 一、内置插件 1.DefinePlugin 2.BannerPlugin 3.ProvidePlugin 一、内置插件 所有的 webpack 内置插件都作为 webpack 的静态属性存在的&#xff0c;使用下面的方式即可创建一个插件对象&#xff1a; const webpack require("webpack")new webpack.插件…

浅谈bypass Etw

文章目录 c#ExecuteAssemblybypass etw c# loader 一种是通过反射找到指定空间的类中method进行Invoke 另一种是通过EntryPoint.Invoke加载 反射加载 Assembly.Load()是从String或AssemblyName类型加载程序集&#xff0c;可以读取字符串形式的程序集 Assembly.LoadFrom()从指定…

JVM内存分析与优化

JVM内存模型分析 在minor gc过程中对象挪动后&#xff0c;引用如何修改&#xff1f; 对象在堆内部挪动的过程其实是复制&#xff0c;原有区域对象还在&#xff0c;一般不直接清理&#xff0c;JVM内部清理过程只是将对象分配指针移动到区域的头位置即可&#xff0c;比如扫描s0区…

零基础学编程从哪里入手,在学习中可以线上会议答疑解惑

一、前言 零基础学编程可以先从容易学的语言入手&#xff0c;比如中文编程&#xff0c;然后再学其他编程语言则会比较轻松&#xff0c;初步掌握编程思路。很多IT人士一般学2到3种编程语言。 今天给大家分享的中文编程开发语言工具资料如下&#xff1a; 编程入门视频教程链接…

速度规划:s形曲线应用(变速 停车)opencv c++显示(3)

理论篇 先看该篇&#xff0c;这里沿用了里面的变量。 应用推导篇 分为变速和停车两部分&#xff08;字迹潦草&#xff0c;可结合代码看&#xff09; 代码篇 变速函数入口&#xff1a; velocityPlanner vp; vp.SetParameters(0, 1);停车函数入口&#xff1a; ParkingVelo…

uniCloud ---- schema2code

目录 schema2code有两种方式 label属性 component属性 group属性 应用 DB Schema里有大量的信息&#xff0c;其实有了这些信息&#xff0c;前端将无需自己开发表单维护界面&#xff0c;uniCloud可以自动生成新增、修改、列表、详情的前端页面&#xff0c;以及admin端的列…

电脑小白必看:如何备份电脑系统?

电脑系统坏了怎么办&#xff1f;扛着自己的笔记本或是台式机的主机去电脑修理店花几十上百重装系统&#xff1f;或是自己用光盘或是U盘启动盘花费数小时重新安装系统&#xff1f;还在为系统问题发愁吗&#xff1f;今天&#xff0c;小编给大家一个简单的方法&#xff0c;让你免去…